added radarr/sonarr attributes and split add_to_arr

pull/165/head
meisnate12 4 years ago
parent 16de1a722e
commit 18dd057548

@ -1293,4 +1293,3 @@ collections:
- ~ - ~
sort_title: ~_Collectionless sort_title: ~_Collectionless
collection_order: alpha collection_order: alpha
collection_order: alpha

@ -30,19 +30,28 @@ tautulli: # Can be individually specified
radarr: # Can be individually specified per library as well radarr: # Can be individually specified per library as well
url: http://192.168.1.12:7878 url: http://192.168.1.12:7878
token: ################################ token: ################################
version: v2 version: v3
quality_profile: HD-1080p
root_folder_path: S:/Movies
add: false add: false
root_folder_path: S:/Movies
monitor: true
availability: announced
quality_profile: HD-1080p
tag:
search: false search: false
sonarr: # Can be individually specified per library as well sonarr: # Can be individually specified per library as well
url: http://192.168.1.12:8989 url: http://192.168.1.12:8989
token: ################################ token: ################################
version: v2 version: v3
quality_profile: HD-1080p
root_folder_path: "S:/TV Shows"
add: false add: false
root_folder_path: "S:/TV Shows"
monitor: all
quality_profile: HD-1080p
language_profile: English
series_type: standard
season_folder: true
tag:
search: false search: false
cutoff_search: false
omdb: omdb:
apikey: ######## apikey: ########
trakt: trakt:

@ -1,6 +1,6 @@
import glob, logging, os, re import glob, logging, os, re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from modules import anidb, anilist, imdb, letterboxd, mal, plex, tautulli, tmdb, trakttv, tvdb, util from modules import anidb, anilist, imdb, letterboxd, mal, plex, radarr, sonarr, tautulli, tmdb, trakttv, tvdb, util
from modules.util import Failed from modules.util import Failed
from plexapi.collection import Collections from plexapi.collection import Collections
from plexapi.exceptions import BadRequest, NotFound from plexapi.exceptions import BadRequest, NotFound
@ -81,13 +81,12 @@ numbered_builders = [
"trakt_collected" "trakt_collected"
] ]
all_details = [ all_details = [
"sort_title", "content_rating", "sort_title", "content_rating", "collection_mode", "collection_order",
"summary", "tmdb_summary", "tmdb_description", "tmdb_biography", "tvdb_summary", "tvdb_description", "trakt_description", "letterboxd_description", "summary", "tmdb_summary", "tmdb_description", "tmdb_biography", "tvdb_summary",
"collection_mode", "collection_order", "tvdb_description", "trakt_description", "letterboxd_description",
"url_poster", "tmdb_poster", "tmdb_profile", "tvdb_poster", "file_poster", "url_poster", "tmdb_poster", "tmdb_profile", "tvdb_poster", "file_poster",
"url_background", "tmdb_background", "tvdb_background", "file_background", "url_background", "tmdb_background", "tvdb_background", "file_background",
"name_mapping", "add_to_arr", "arr_tag", "arr_folder", "label", "name_mapping", "label", "show_filtered", "show_missing", "save_missing"
"show_filtered", "show_missing", "save_missing"
] ]
collectionless_details = [ collectionless_details = [
"sort_title", "content_rating", "sort_title", "content_rating",
@ -106,7 +105,6 @@ ignored_details = [
"tmdb_person" "tmdb_person"
] ]
boolean_details = [ boolean_details = [
"add_to_arr",
"show_filtered", "show_filtered",
"show_missing", "show_missing",
"save_missing" "save_missing"
@ -152,12 +150,12 @@ class CollectionBuilder:
self.name = name self.name = name
self.data = data self.data = data
self.details = { self.details = {
"arr_tag": None,
"arr_folder": None,
"show_filtered": library.show_filtered, "show_filtered": library.show_filtered,
"show_missing": library.show_missing, "show_missing": library.show_missing,
"save_missing": library.save_missing "save_missing": library.save_missing
} }
self.radarr_options = {}
self.sonarr_options = {}
self.missing_movies = [] self.missing_movies = []
self.missing_shows = [] self.missing_shows = []
self.methods = [] self.methods = []
@ -167,6 +165,8 @@ class CollectionBuilder:
self.summaries = {} self.summaries = {}
self.schedule = "" self.schedule = ""
self.rating_key_map = {} self.rating_key_map = {}
self.add_to_radarr = None
self.add_to_sonarr = None
current_time = datetime.now() current_time = datetime.now()
current_year = current_time.year current_year = current_time.year
@ -355,20 +355,28 @@ class CollectionBuilder:
else: else:
raise Failed("Collection Error: tmdb_person attribute is blank") raise Failed("Collection Error: tmdb_person attribute is blank")
for method_name, method_data in self.data.items(): for method_key, method_data in self.data.items():
if "trakt" in method_name.lower() and not config.Trakt: raise Failed(f"Collection Error: {method_name} requires Trakt todo be configured") if "trakt" in method_key.lower() and not config.Trakt: raise Failed(f"Collection Error: {method_key} requires Trakt todo be configured")
elif "imdb" in method_name.lower() and not config.IMDb: raise Failed(f"Collection Error: {method_name} requires TMDb or Trakt to be configured") elif "imdb" in method_key.lower() and not config.IMDb: raise Failed(f"Collection Error: {method_key} requires TMDb or Trakt to be configured")
elif "tautulli" in method_name.lower() and not self.library.Tautulli: raise Failed(f"Collection Error: {method_name} requires Tautulli to be configured") elif "radarr" in method_key.lower() and not self.library.Radarr: raise Failed(f"Collection Error: {method_key} requires Radarr to be configured")
elif "mal" in method_name.lower() and not config.MyAnimeList: raise Failed(f"Collection Error: {method_name} requires MyAnimeList to be configured") elif "sonarr" in method_key.lower() and not self.library.Sonarr: raise Failed(f"Collection Error: {method_key} requires Sonarr to be configured")
elif "tautulli" in method_key.lower() and not self.library.Tautulli: raise Failed(f"Collection Error: {method_key} requires Tautulli to be configured")
elif "mal" in method_key.lower() and not config.MyAnimeList: raise Failed(f"Collection Error: {method_key} requires MyAnimeList to be configured")
elif method_data is not None: elif method_data is not None:
logger.debug("") logger.debug("")
logger.debug(f"Validating Method: {method_name}") logger.debug(f"Validating Method: {method_key}")
logger.debug(f"Value: {method_data}") logger.debug(f"Value: {method_data}")
if method_name.lower() in method_alias: if method_key.lower() in method_alias:
method_name = method_alias[method_name.lower()] method_name = method_alias[method_key.lower()]
logger.warning(f"Collection Warning: {method_name} attribute will run as {method_name}") logger.warning(f"Collection Warning: {method_key} attribute will run as {method_name}")
else: elif method_key.lower() == "add_to_arr":
method_name = method_name.lower() method_name = "radarr_add" if self.library.is_movie else "sonarr_add"
logger.warning(f"Collection Warning: {method_key} attribute will run as {method_name}")
elif method_key.lower() in ["arr_tag", "arr_folder"]:
method_name = f"{'rad' if self.library.is_movie else 'son'}{method_key.lower()}"
logger.warning(f"Collection Warning: {method_key} attribute will run as {method_name}")
else:
method_name = method_key.lower()
if method_name in show_only_builders and self.library.is_movie: if method_name in show_only_builders and self.library.is_movie:
raise Failed(f"Collection Error: {method_name} attribute only works for show libraries") raise Failed(f"Collection Error: {method_name} attribute only works for show libraries")
elif method_name in movie_only_builders and self.library.is_show: elif method_name in movie_only_builders and self.library.is_show:
@ -441,7 +449,7 @@ class CollectionBuilder:
elif method_name == "sync_mode": elif method_name == "sync_mode":
if str(method_data).lower() in ["append", "sync"]: self.details[method_name] = method_data.lower() if str(method_data).lower() in ["append", "sync"]: self.details[method_name] = method_data.lower()
else: raise Failed("Collection Error: sync_mode attribute must be either 'append' or 'sync'") else: raise Failed("Collection Error: sync_mode attribute must be either 'append' or 'sync'")
elif method_name in ["arr_tag", "label"]: elif method_name == "label":
self.details[method_name] = util.get_list(method_data) self.details[method_name] = util.get_list(method_data)
elif method_name in boolean_details: elif method_name in boolean_details:
if isinstance(method_data, bool): self.details[method_name] = method_data if isinstance(method_data, bool): self.details[method_name] = method_data
@ -450,6 +458,52 @@ class CollectionBuilder:
else: raise Failed(f"Collection Error: {method_name} attribute must be either true or false") else: raise Failed(f"Collection Error: {method_name} attribute must be either true or false")
elif method_name in all_details: elif method_name in all_details:
self.details[method_name] = method_data self.details[method_name] = method_data
elif method_name == "radarr_add":
self.add_to_radarr = True
elif method_name == "radarr_folder":
self.radarr_options["folder"] = method_data
elif method_name in ["radarr_monitor", "radarr_search"]:
if isinstance(method_data, bool): self.radarr_options[method_name[7:]] = method_data
elif str(method_data).lower() in ["t", "true"]: self.radarr_options[method_name[7:]] = True
elif str(method_data).lower() in ["f", "false"]: self.radarr_options[method_name[7:]] = False
else: raise Failed(f"Collection Error: {method_name} attribute must be either true or false")
elif method_name == "radarr_availability":
if str(method_data).lower() in radarr.availability_translation:
self.radarr_options["availability"] = str(method_data).lower()
else:
raise Failed(f"Collection Error: {method_name} attribute must be either announced, cinemas, released or db")
elif method_name == "radarr_quality":
self.library.Radarr.get_profile_id(method_data)
self.radarr_options["quality"] = method_data
elif method_name == "radarr_tag":
self.radarr_options["tag"] = util.get_list(method_data)
elif method_name == "sonarr_add":
self.add_to_sonarr = True
elif method_name == "sonarr_folder":
self.sonarr_options["folder"] = method_data
elif method_name == "sonarr_monitor":
if str(method_data).lower() in sonarr.monitor_translation:
self.sonarr_options["monitor"] = str(method_data).lower()
else:
raise Failed(f"Collection Error: {method_name} attribute must be either all, future, missing, existing, pilot, first, latest or none")
elif method_name == "sonarr_quality":
self.library.Sonarr.get_profile_id(method_data, "quality_profile")
self.sonarr_options["quality"] = method_data
elif method_name == "sonarr_language":
self.library.Sonarr.get_profile_id(method_data, "language_profile")
self.sonarr_options["language"] = method_data
elif method_name == "sonarr_series":
if str(method_data).lower() in sonarr.series_type:
self.sonarr_options["series"] = str(method_data).lower()
else:
raise Failed(f"Collection Error: {method_name} attribute must be either standard, daily, or anime")
elif method_name in ["sonarr_season", "sonarr_search", "sonarr_cutoff_search"]:
if isinstance(method_data, bool): self.sonarr_options[method_name[7:]] = method_data
elif str(method_data).lower() in ["t", "true"]: self.sonarr_options[method_name[7:]] = True
elif str(method_data).lower() in ["f", "false"]: self.sonarr_options[method_name[7:]] = False
else: raise Failed(f"Collection Error: {method_name} attribute must be either true or false")
elif method_name == "sonarr_tag":
self.sonarr_options["tag"] = util.get_list(method_data)
elif method_name in ["title", "title.and", "title.not", "title.begins", "title.ends"]: elif method_name in ["title", "title.and", "title.not", "title.begins", "title.ends"]:
self.methods.append(("plex_search", [{method_name: util.get_list(method_data, split=False)}])) self.methods.append(("plex_search", [{method_name: util.get_list(method_data, split=False)}]))
elif method_name in ["year.greater", "year.less"]: elif method_name in ["year.greater", "year.less"]:
@ -898,10 +952,10 @@ class CollectionBuilder:
self.methods.append((method_name, util.get_list(method_data))) self.methods.append((method_name, util.get_list(method_data)))
elif method_name not in ignored_details: elif method_name not in ignored_details:
raise Failed(f"Collection Error: {method_name} attribute not supported") raise Failed(f"Collection Error: {method_name} attribute not supported")
elif method_name in all_builders or method_name in method_alias or method_name in plex.searches: elif method_key.lower() in all_builders or method_key.lower() in method_alias or method_key.lower() in plex.searches:
raise Failed(f"Collection Error: {method_name} attribute is blank") raise Failed(f"Collection Error: {method_key} attribute is blank")
else: else:
logger.warning(f"Collection Warning: {method_name} attribute is blank") logger.warning(f"Collection Warning: {method_key} attribute is blank")
self.sync = self.library.sync_mode == "sync" self.sync = self.library.sync_mode == "sync"
if "sync_mode" in methods: if "sync_mode" in methods:
@ -912,14 +966,14 @@ class CollectionBuilder:
else: else:
self.sync = self.data[methods["sync_mode"]].lower() == "sync" self.sync = self.data[methods["sync_mode"]].lower() == "sync"
self.do_arr = False if self.add_to_radarr is None:
if self.library.Radarr: self.add_to_radarr = self.library.Radarr.add if self.library.Radarr else False
self.do_arr = self.details["add_to_arr"] if "add_to_arr" in self.details else self.library.Radarr.add if self.add_to_sonarr is None:
if self.library.Sonarr: self.add_to_sonarr = self.library.Sonarr.add if self.library.Sonarr else False
self.do_arr = self.details["add_to_arr"] if "add_to_arr" in self.details else self.library.Sonarr.add
if self.collectionless: if self.collectionless:
self.details["add_to_arr"] = False self.add_to_radarr = False
self.add_to_sonarr = False
self.details["collection_mode"] = "hide" self.details["collection_mode"] = "hide"
self.sync = True self.sync = True
@ -1001,8 +1055,11 @@ class CollectionBuilder:
logger.info(f"{len(missing_movies_with_names)} Movie{'s' if len(missing_movies_with_names) > 1 else ''} Missing") logger.info(f"{len(missing_movies_with_names)} Movie{'s' if len(missing_movies_with_names) > 1 else ''} Missing")
if self.details["save_missing"] is True: if self.details["save_missing"] is True:
self.library.add_missing(collection_name, missing_movies_with_names, True) self.library.add_missing(collection_name, missing_movies_with_names, True)
if self.do_arr and self.library.Radarr: if self.add_to_radarr and self.library.Radarr:
self.library.Radarr.add_tmdb([missing_id for title, missing_id in missing_movies_with_names], tags=self.details["arr_tag"], folder=self.details["arr_folder"]) try:
self.library.Radarr.add_tmdb([missing_id for title, missing_id in missing_movies_with_names], **self.radarr_options)
except Failed as e:
logger.error(e)
if self.run_again: if self.run_again:
self.missing_movies.extend([missing_id for title, missing_id in missing_movies_with_names]) self.missing_movies.extend([missing_id for title, missing_id in missing_movies_with_names])
if len(missing_shows) > 0 and self.library.is_show: if len(missing_shows) > 0 and self.library.is_show:
@ -1030,8 +1087,11 @@ class CollectionBuilder:
logger.info(f"{len(missing_shows_with_names)} Show{'s' if len(missing_shows_with_names) > 1 else ''} Missing") logger.info(f"{len(missing_shows_with_names)} Show{'s' if len(missing_shows_with_names) > 1 else ''} Missing")
if self.details["save_missing"] is True: if self.details["save_missing"] is True:
self.library.add_missing(collection_name, missing_shows_with_names, False) self.library.add_missing(collection_name, missing_shows_with_names, False)
if self.do_arr and self.library.Sonarr: if self.add_to_sonarr and self.library.Sonarr:
self.library.Sonarr.add_tvdb([missing_id for title, missing_id in missing_shows_with_names], tags=self.details["arr_tag"], folder=self.details["arr_folder"]) try:
self.library.Sonarr.add_tvdb([missing_id for title, missing_id in missing_shows_with_names], **self.sonarr_options)
except Failed as e:
logger.error(e)
if self.run_again: if self.run_again:
self.missing_shows.extend([missing_id for title, missing_id in missing_shows_with_names]) self.missing_shows.extend([missing_id for title, missing_id in missing_shows_with_names])

@ -24,7 +24,28 @@ logger = logging.getLogger("Plex Meta Manager")
sync_modes = {"append": "Only Add Items to the Collection", "sync": "Add & Remove Items from the Collection"} sync_modes = {"append": "Only Add Items to the Collection", "sync": "Add & Remove Items from the Collection"}
radarr_versions = {"v2": "For Radarr 0.2", "v3": "For Radarr 3.0"} radarr_versions = {"v2": "For Radarr 0.2", "v3": "For Radarr 3.0"}
radarr_availabilities = {
"announced": "For Announced",
"cinemas": "For In Cinemas",
"released": "For Released",
"db": "For PreDB"
}
sonarr_versions = {"v2": "For Sonarr 0.2", "v3": "For Sonarr 3.0"} sonarr_versions = {"v2": "For Sonarr 0.2", "v3": "For Sonarr 3.0"}
sonarr_monitors = {
"all": "Monitor all episodes except specials",
"future": "Monitor episodes that have not aired yet",
"missing": "Monitor episodes that do not have files or have not aired yet",
"existing": "Monitor episodes that have files or have not aired yet",
"pilot": "Monitor the first episode. All other episodes will be ignored",
"first": "Monitor all episodes of the first season. All other seasons will be ignored",
"latest": "Monitor all episodes of the latest season and future seasons",
"none": "No episodes will be monitored"
}
sonarr_series_types = {
"standard": "Episodes released with SxxEyy pattern",
"daily": "Episodes released daily or less frequently that use year-month-day (2017-05-25)",
"anime": "Episodes released using an absolute episode number"
}
mass_genre_update_options = {"tmdb": "Use TMDb Metadata", "omdb": "Use IMDb Metadata through OMDb"} mass_genre_update_options = {"tmdb": "Use TMDb Metadata", "omdb": "Use IMDb Metadata through OMDb"}
library_types = {"movie": "For Movie Libraries", "show": "For Show Libraries"} library_types = {"movie": "For Movie Libraries", "show": "For Show Libraries"}
@ -257,9 +278,11 @@ class Config:
self.general["radarr"] = {} self.general["radarr"] = {}
self.general["radarr"]["url"] = check_for_attribute(self.data, "url", parent="radarr", default_is_none=True) self.general["radarr"]["url"] = check_for_attribute(self.data, "url", parent="radarr", default_is_none=True)
self.general["radarr"]["token"] = check_for_attribute(self.data, "token", parent="radarr", default_is_none=True) self.general["radarr"]["token"] = check_for_attribute(self.data, "token", parent="radarr", default_is_none=True)
self.general["radarr"]["version"] = check_for_attribute(self.data, "version", parent="radarr", test_list=radarr_versions, default="v2") self.general["radarr"]["version"] = check_for_attribute(self.data, "version", parent="radarr", test_list=radarr_versions, default="v3")
self.general["radarr"]["add"] = check_for_attribute(self.data, "add", parent="radarr", var_type="bool", default=False) self.general["radarr"]["add"] = check_for_attribute(self.data, "add", parent="radarr", var_type="bool", default=False)
self.general["radarr"]["root_folder_path"] = check_for_attribute(self.data, "root_folder_path", parent="radarr", default_is_none=True) self.general["radarr"]["root_folder_path"] = check_for_attribute(self.data, "root_folder_path", parent="radarr", default_is_none=True)
self.general["radarr"]["monitor"] = check_for_attribute(self.data, "monitor", parent="radarr", var_type="bool", default=True)
self.general["radarr"]["availability"] = check_for_attribute(self.data, "availability", parent="radarr", test_list=radarr_availabilities, default="announced")
self.general["radarr"]["quality_profile"] = check_for_attribute(self.data, "quality_profile", parent="radarr", default_is_none=True) self.general["radarr"]["quality_profile"] = check_for_attribute(self.data, "quality_profile", parent="radarr", default_is_none=True)
self.general["radarr"]["tag"] = check_for_attribute(self.data, "tag", parent="radarr", var_type="lower_list", default_is_none=True) self.general["radarr"]["tag"] = check_for_attribute(self.data, "tag", parent="radarr", var_type="lower_list", default_is_none=True)
self.general["radarr"]["search"] = check_for_attribute(self.data, "search", parent="radarr", var_type="bool", default=False) self.general["radarr"]["search"] = check_for_attribute(self.data, "search", parent="radarr", var_type="bool", default=False)
@ -267,14 +290,17 @@ class Config:
self.general["sonarr"] = {} self.general["sonarr"] = {}
self.general["sonarr"]["url"] = check_for_attribute(self.data, "url", parent="sonarr", default_is_none=True) self.general["sonarr"]["url"] = check_for_attribute(self.data, "url", parent="sonarr", default_is_none=True)
self.general["sonarr"]["token"] = check_for_attribute(self.data, "token", parent="sonarr", default_is_none=True) self.general["sonarr"]["token"] = check_for_attribute(self.data, "token", parent="sonarr", default_is_none=True)
self.general["sonarr"]["version"] = check_for_attribute(self.data, "version", parent="sonarr", test_list=sonarr_versions, default="v2") self.general["sonarr"]["version"] = check_for_attribute(self.data, "version", parent="sonarr", test_list=sonarr_versions, default="v3")
self.general["sonarr"]["quality_profile"] = check_for_attribute(self.data, "quality_profile", parent="sonarr", default_is_none=True) self.general["sonarr"]["add"] = check_for_attribute(self.data, "add", parent="sonarr", var_type="bool", default=False)
self.general["sonarr"]["root_folder_path"] = check_for_attribute(self.data, "root_folder_path", parent="sonarr", default_is_none=True) self.general["sonarr"]["root_folder_path"] = check_for_attribute(self.data, "root_folder_path", parent="sonarr", default_is_none=True)
self.general["sonarr"]["monitor"] = check_for_attribute(self.data, "monitor", parent="sonarr", test_list=sonarr_monitors, default="all")
self.general["sonarr"]["quality_profile"] = check_for_attribute(self.data, "quality_profile", parent="sonarr", default_is_none=True)
self.general["sonarr"]["language_profile"] = check_for_attribute(self.data, "language_profile", parent="sonarr", default_is_none=True) self.general["sonarr"]["language_profile"] = check_for_attribute(self.data, "language_profile", parent="sonarr", default_is_none=True)
self.general["sonarr"]["add"] = check_for_attribute(self.data, "add", parent="sonarr", var_type="bool", default=False) self.general["sonarr"]["series_type"] = check_for_attribute(self.data, "series_type", parent="sonarr", test_list=sonarr_series_types, default="standard")
self.general["sonarr"]["search"] = check_for_attribute(self.data, "search", parent="sonarr", var_type="bool", default=False)
self.general["sonarr"]["season_folder"] = check_for_attribute(self.data, "season_folder", parent="sonarr", var_type="bool", default=True) self.general["sonarr"]["season_folder"] = check_for_attribute(self.data, "season_folder", parent="sonarr", var_type="bool", default=True)
self.general["sonarr"]["tag"] = check_for_attribute(self.data, "tag", parent="sonarr", var_type="lower_list", default_is_none=True) self.general["sonarr"]["tag"] = check_for_attribute(self.data, "tag", parent="sonarr", var_type="lower_list", default_is_none=True)
self.general["sonarr"]["search"] = check_for_attribute(self.data, "search", parent="sonarr", var_type="bool", default=False)
self.general["sonarr"]["cutoff_search"] = check_for_attribute(self.data, "cutoff_search", parent="sonarr", var_type="bool", default=False)
self.general["tautulli"] = {} self.general["tautulli"] = {}
self.general["tautulli"]["url"] = check_for_attribute(self.data, "url", parent="tautulli", default_is_none=True) self.general["tautulli"]["url"] = check_for_attribute(self.data, "url", parent="tautulli", default_is_none=True)
@ -354,6 +380,8 @@ class Config:
radarr_params["version"] = check_for_attribute(lib, "version", parent="radarr", test_list=radarr_versions, default=self.general["radarr"]["version"], save=False) radarr_params["version"] = check_for_attribute(lib, "version", parent="radarr", test_list=radarr_versions, default=self.general["radarr"]["version"], save=False)
radarr_params["add"] = check_for_attribute(lib, "add", parent="radarr", var_type="bool", default=self.general["radarr"]["add"], save=False) radarr_params["add"] = check_for_attribute(lib, "add", parent="radarr", var_type="bool", default=self.general["radarr"]["add"], save=False)
radarr_params["root_folder_path"] = check_for_attribute(lib, "root_folder_path", parent="radarr", default=self.general["radarr"]["root_folder_path"], req_default=True, save=False) radarr_params["root_folder_path"] = check_for_attribute(lib, "root_folder_path", parent="radarr", default=self.general["radarr"]["root_folder_path"], req_default=True, save=False)
radarr_params["monitor"] = check_for_attribute(lib, "monitor", parent="radarr", var_type="bool", default=self.general["radarr"]["monitor"], save=False)
radarr_params["availability"] = check_for_attribute(lib, "availability", parent="radarr", test_list=radarr_availabilities, default=self.general["radarr"]["availability"], save=False)
radarr_params["quality_profile"] = check_for_attribute(lib, "quality_profile", parent="radarr", default=self.general["radarr"]["quality_profile"], req_default=True, save=False) radarr_params["quality_profile"] = check_for_attribute(lib, "quality_profile", parent="radarr", default=self.general["radarr"]["quality_profile"], req_default=True, save=False)
radarr_params["tag"] = check_for_attribute(lib, "search", parent="radarr", var_type="lower_list", default=self.general["radarr"]["tag"], default_is_none=True, save=False) radarr_params["tag"] = check_for_attribute(lib, "search", parent="radarr", var_type="lower_list", default=self.general["radarr"]["tag"], default_is_none=True, save=False)
radarr_params["search"] = check_for_attribute(lib, "search", parent="radarr", var_type="bool", default=self.general["radarr"]["search"], save=False) radarr_params["search"] = check_for_attribute(lib, "search", parent="radarr", var_type="bool", default=self.general["radarr"]["search"], save=False)
@ -369,16 +397,19 @@ class Config:
sonarr_params["url"] = check_for_attribute(lib, "url", parent="sonarr", default=self.general["sonarr"]["url"], req_default=True, save=False) sonarr_params["url"] = check_for_attribute(lib, "url", parent="sonarr", default=self.general["sonarr"]["url"], req_default=True, save=False)
sonarr_params["token"] = check_for_attribute(lib, "token", parent="sonarr", default=self.general["sonarr"]["token"], req_default=True, save=False) sonarr_params["token"] = check_for_attribute(lib, "token", parent="sonarr", default=self.general["sonarr"]["token"], req_default=True, save=False)
sonarr_params["version"] = check_for_attribute(lib, "version", parent="sonarr", test_list=sonarr_versions, default=self.general["sonarr"]["version"], save=False) sonarr_params["version"] = check_for_attribute(lib, "version", parent="sonarr", test_list=sonarr_versions, default=self.general["sonarr"]["version"], save=False)
sonarr_params["quality_profile"] = check_for_attribute(lib, "quality_profile", parent="sonarr", default=self.general["sonarr"]["quality_profile"], req_default=True, save=False) sonarr_params["add"] = check_for_attribute(lib, "add", parent="sonarr", var_type="bool", default=self.general["sonarr"]["add"], save=False)
sonarr_params["root_folder_path"] = check_for_attribute(lib, "root_folder_path", parent="sonarr", default=self.general["sonarr"]["root_folder_path"], req_default=True, save=False) sonarr_params["root_folder_path"] = check_for_attribute(lib, "root_folder_path", parent="sonarr", default=self.general["sonarr"]["root_folder_path"], req_default=True, save=False)
sonarr_params["monitor"] = check_for_attribute(lib, "monitor", parent="sonarr", test_list=sonarr_monitors, default=self.general["sonarr"]["monitor"], save=False)
sonarr_params["quality_profile"] = check_for_attribute(lib, "quality_profile", parent="sonarr", default=self.general["sonarr"]["quality_profile"], req_default=True, save=False)
if self.general["sonarr"]["language_profile"]: if self.general["sonarr"]["language_profile"]:
sonarr_params["language_profile"] = check_for_attribute(lib, "language_profile", parent="sonarr", default=self.general["sonarr"]["language_profile"], save=False) sonarr_params["language_profile"] = check_for_attribute(lib, "language_profile", parent="sonarr", default=self.general["sonarr"]["language_profile"], save=False)
else: else:
sonarr_params["language_profile"] = check_for_attribute(lib, "language_profile", parent="sonarr", default_is_none=True, save=False) sonarr_params["language_profile"] = check_for_attribute(lib, "language_profile", parent="sonarr", default_is_none=True, save=False)
sonarr_params["add"] = check_for_attribute(lib, "add", parent="sonarr", var_type="bool", default=self.general["sonarr"]["add"], save=False) sonarr_params["series_type"] = check_for_attribute(lib, "series_type", parent="sonarr", test_list=sonarr_series_types, default=self.general["sonarr"]["series_type"], save=False)
sonarr_params["search"] = check_for_attribute(lib, "search", parent="sonarr", var_type="bool", default=self.general["sonarr"]["search"], save=False)
sonarr_params["season_folder"] = check_for_attribute(lib, "season_folder", parent="sonarr", var_type="bool", default=self.general["sonarr"]["season_folder"], save=False) sonarr_params["season_folder"] = check_for_attribute(lib, "season_folder", parent="sonarr", var_type="bool", default=self.general["sonarr"]["season_folder"], save=False)
sonarr_params["tag"] = check_for_attribute(lib, "search", parent="sonarr", var_type="lower_list", default=self.general["sonarr"]["tag"], default_is_none=True, save=False) sonarr_params["tag"] = check_for_attribute(lib, "search", parent="sonarr", var_type="lower_list", default=self.general["sonarr"]["tag"], default_is_none=True, save=False)
sonarr_params["search"] = check_for_attribute(lib, "search", parent="sonarr", var_type="bool", default=self.general["sonarr"]["search"], save=False)
sonarr_params["cutoff_search"] = check_for_attribute(lib, "cutoff_search", parent="sonarr", var_type="bool", default=self.general["sonarr"]["cutoff_search"], save=False)
library.Sonarr = SonarrAPI(sonarr_params, library.Plex.language) library.Sonarr = SonarrAPI(sonarr_params, library.Plex.language)
except Failed as e: except Failed as e:
util.print_multiline(e, error=True) util.print_multiline(e, error=True)

@ -5,37 +5,46 @@ from retrying import retry
logger = logging.getLogger("Plex Meta Manager") logger = logging.getLogger("Plex Meta Manager")
availability_translation = {
"announced": "announced",
"cinemas": "inCinemas",
"released": "released",
"db": "preDB"
}
class RadarrAPI: class RadarrAPI:
def __init__(self, params): def __init__(self, params):
self.base_url = f"{params['url']}/api{'/v3' if params['version'] == 'v3' else ''}/" self.url = params["url"]
self.token = params["token"] self.token = params["token"]
self.version = params["version"]
self.base_url = f"{self.url}/api{'/v3' if self.version == 'v3' else ''}/"
try: try:
result = requests.get(f"{self.base_url}system/status", params={"apikey": f"{self.token}"}).json() result = requests.get(f"{self.base_url}system/status", params={"apikey": f"{self.token}"}).json()
except Exception: except Exception:
util.print_stacktrace() util.print_stacktrace()
raise Failed(f"Radarr Error: Could not connect to Radarr at {params['url']}") raise Failed(f"Radarr Error: Could not connect to Radarr at {self.url}")
if "error" in result and result["error"] == "Unauthorized": if "error" in result and result["error"] == "Unauthorized":
raise Failed("Radarr Error: Invalid API Key") raise Failed("Radarr Error: Invalid API Key")
if "version" not in result: if "version" not in result:
raise Failed("Radarr Error: Unexpected Response Check URL") raise Failed("Radarr Error: Unexpected Response Check URL")
self.quality_profile_id = None self.add = params["add"]
self.root_folder_path = params["root_folder_path"]
self.monitor = params["monitor"]
self.availability = params["availability"]
self.quality_profile_id = self.get_profile_id(params["quality_profile"])
self.tag = params["tag"]
self.tags = self.get_tags()
self.search = params["search"]
def get_profile_id(self, profile_name):
profiles = "" profiles = ""
for profile in self.send_get("qualityProfile" if params["version"] == "v3" else "profile"): for profile in self.send_get("qualityProfile" if self.version == "v3" else "profile"):
if len(profiles) > 0: if len(profiles) > 0:
profiles += ", " profiles += ", "
profiles += profile["name"] profiles += profile["name"]
if profile["name"] == params["quality_profile"]: if profile["name"] == profile_name:
self.quality_profile_id = profile["id"] return profile["id"]
if not self.quality_profile_id: raise Failed(f"Radarr Error: quality_profile: {profile_name} does not exist in radarr. Profiles available: {profiles}")
raise Failed(f"Radarr Error: quality_profile: {params['quality_profile']} does not exist in radarr. Profiles available: {profiles}")
self.tags = self.get_tags()
self.url = params["url"]
self.version = params["version"]
self.token = params["token"]
self.root_folder_path = params["root_folder_path"]
self.add = params["add"]
self.search = params["search"]
self.tag = params["tag"]
def get_tags(self): def get_tags(self):
return {tag["label"]: tag["id"] for tag in self.send_get("tag")} return {tag["label"]: tag["id"] for tag in self.send_get("tag")}
@ -56,13 +65,17 @@ class RadarrAPI:
else: else:
raise Failed(f"Sonarr Error: TMDb ID: {tmdb_id} not found") raise Failed(f"Sonarr Error: TMDb ID: {tmdb_id} not found")
def add_tmdb(self, tmdb_ids, tags=None, folder=None): def add_tmdb(self, tmdb_ids, **options):
logger.info("") logger.info("")
logger.debug(f"TMDb IDs: {tmdb_ids}") logger.debug(f"TMDb IDs: {tmdb_ids}")
tag_nums = [] tag_nums = []
add_count = 0 add_count = 0
if tags is None: folder = options["folder"] if "folder" in options else self.root_folder_path
tags = self.tag monitor = options["monitor"] if "monitor" in options else self.monitor
availability = options["availability"] if "availability" in options else self.availability
quality_profile_id = self.get_profile_id(options["quality"]) if "quality" in options else self.quality_profile_id
tags = options["tag"] if "tag" in options else self.tag
search = options["search"] if "search" in options else self.search
if tags: if tags:
self.add_tags(tags) self.add_tags(tags)
tag_nums = [self.tags[label] for label in tags if label in self.tags] tag_nums = [self.tags[label] for label in tags if label in self.tags]
@ -80,14 +93,15 @@ class RadarrAPI:
url_json = { url_json = {
"title": movie_info["title"], "title": movie_info["title"],
f"{'qualityProfileId' if self.version == 'v3' else 'profileId'}": self.quality_profile_id, f"{'qualityProfileId' if self.version == 'v3' else 'profileId'}": quality_profile_id,
"year": int(movie_info["year"]), "year": int(movie_info["year"]),
"tmdbid": int(tmdb_id), "tmdbid": int(tmdb_id),
"titleslug": movie_info["titleSlug"], "titleslug": movie_info["titleSlug"],
"monitored": True, "minimumAvailability": availability_translation[availability],
"rootFolderPath": self.root_folder_path if folder is None else folder, "monitored": monitor,
"rootFolderPath": folder,
"images": [{"covertype": "poster", "url": poster_url}], "images": [{"covertype": "poster", "url": poster_url}],
"addOptions": {"searchForMovie": self.search} "addOptions": {"searchForMovie": search}
} }
if tag_nums: if tag_nums:
url_json["tags"] = tag_nums url_json["tags"] = tag_nums

@ -5,53 +5,65 @@ from retrying import retry
logger = logging.getLogger("Plex Meta Manager") 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"
}
class SonarrAPI: class SonarrAPI:
def __init__(self, params, language): def __init__(self, params, language):
self.base_url = f"{params['url']}/api{'/v3/' if params['version'] == 'v3' else '/'}" self.url = params["url"]
self.token = params["token"] self.token = params["token"]
self.version = params["version"]
self.base_url = f"{self.url}/api{'/v3/' if self.version == 'v3' else '/'}"
try: try:
result = requests.get(f"{self.base_url}system/status", params={"apikey": f"{self.token}"}).json() result = requests.get(f"{self.base_url}system/status", params={"apikey": f"{self.token}"}).json()
except Exception: except Exception:
util.print_stacktrace() util.print_stacktrace()
raise Failed(f"Sonarr Error: Could not connect to Sonarr at {params['url']}") raise Failed(f"Sonarr Error: Could not connect to Sonarr at {self.url}")
if "error" in result and result["error"] == "Unauthorized": if "error" in result and result["error"] == "Unauthorized":
raise Failed("Sonarr Error: Invalid API Key") raise Failed("Sonarr Error: Invalid API Key")
if "version" not in result: if "version" not in result:
raise Failed("Sonarr Error: Unexpected Response Check URL") raise Failed("Sonarr Error: Unexpected Response Check URL")
self.quality_profile_id = None self.add = params["add"]
profiles = "" self.root_folder_path = params["root_folder_path"]
for profile in self.send_get("qualityProfile" if params["version"] == "v3" else "profile"): self.monitor = params["monitor"]
if len(profiles) > 0: self.quality_profile_id = self.get_profile_id(params["quality_profile"], "quality_profile")
profiles += ", "
profiles += profile["name"]
if profile["name"] == params["quality_profile"]:
self.quality_profile_id = profile["id"]
if not self.quality_profile_id:
raise Failed(f"Sonarr Error: quality_profile: {params['quality_profile']} does not exist in sonarr. Profiles available: {profiles}")
self.language_profile_id = None self.language_profile_id = None
if params["version"] == "v3" and params["language_profile"] is not None: if self.version == "v3" and params["language_profile"] is not None:
profiles = "" self.language_profile_id = self.get_profile_id(params["language_profile"], "language_profile")
for profile in self.send_get("languageProfile"):
if len(profiles) > 0:
profiles += ", "
profiles += profile["name"]
if profile["name"] == params["language_profile"]:
self.language_profile_id = profile["id"]
if not self.quality_profile_id:
raise Failed(f"Sonarr Error: language_profile: {params['language_profile']} does not exist in sonarr. Profiles available: {profiles}")
if self.language_profile_id is None: if self.language_profile_id is None:
self.language_profile_id = 1 self.language_profile_id = 1
self.series_type = params["series_type"]
self.tags = self.get_tags()
self.language = language
self.version = params["version"]
self.root_folder_path = params["root_folder_path"]
self.add = params["add"]
self.search = params["search"]
self.season_folder = params["season_folder"] self.season_folder = params["season_folder"]
self.tag = params["tag"] 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"
for profile in self.send_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}")
def get_tags(self): def get_tags(self):
return {tag["label"]: tag["id"] for tag in self.send_get("tag")} return {tag["label"]: tag["id"] for tag in self.send_get("tag")}
@ -72,13 +84,20 @@ class SonarrAPI:
else: else:
raise Failed(f"Sonarr Error: TVDb ID: {tvdb_id} not found") raise Failed(f"Sonarr Error: TVDb ID: {tvdb_id} not found")
def add_tvdb(self, tvdb_ids, tags=None, folder=None): def add_tvdb(self, tvdb_ids, **options):
logger.info("") logger.info("")
logger.debug(f"TVDb IDs: {tvdb_ids}") logger.debug(f"TVDb IDs: {tvdb_ids}")
tag_nums = [] tag_nums = []
add_count = 0 add_count = 0
if tags is None: folder = options["folder"] if "folder" in options else self.root_folder_path
tags = self.tag 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
language_profile_id = self.get_profile_id(options["language"], "language_profile") if "quality" in options else self.quality_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
if tags: if tags:
self.add_tags(tags) self.add_tags(tags)
tag_nums = [self.tags[label] for label in tags if label in self.tags] tag_nums = [self.tags[label] for label in tags if label in self.tags]
@ -96,17 +115,22 @@ class SonarrAPI:
url_json = { url_json = {
"title": show_info["title"], "title": show_info["title"],
f"{'qualityProfileId' if self.version == 'v3' else 'profileId'}": self.quality_profile_id, f"{'qualityProfileId' if self.version == 'v3' else 'profileId'}": quality_profile_id,
"languageProfileId": self.language_profile_id, "languageProfileId": language_profile_id,
"tvdbId": int(tvdb_id), "tvdbId": int(tvdb_id),
"titleslug": show_info["titleSlug"], "titleslug": show_info["titleSlug"],
"language": self.language, "language": self.language,
"monitored": True, "monitored": monitor != "none",
"seasonFolder": self.season_folder, "seasonFolder": season,
"rootFolderPath": self.root_folder_path if folder is None else folder, "seriesType": series,
"rootFolderPath": folder,
"seasons": [], "seasons": [],
"images": [{"covertype": "poster", "url": poster_url}], "images": [{"covertype": "poster", "url": poster_url}],
"addOptions": {"searchForMissingEpisodes": self.search} "addOptions": {
"searchForMissingEpisodes": search,
"searchForCutoffUnmetEpisodes": cutoff_search,
"monitor": monitor_translation[monitor]
}
} }
if tag_nums: if tag_nums:
url_json["tags"] = tag_nums url_json["tags"] = tag_nums

Loading…
Cancel
Save