[32] Sonarr v4 support

pull/1203/head
meisnate12 2 years ago
parent 5103a576db
commit a26ff42f0a

@ -1 +1 @@
1.18.0-develop31
1.18.0-develop32

@ -34,7 +34,7 @@ dynamic_collections:
search_term:
default: genre
image:
default: genre/<<key_name_encoded>>
default: genre/<<original_key_name_encoded>>
translation_key:
default: genre
addons:

@ -41,7 +41,7 @@ dynamic_collections:
search_term:
default: country
image:
default: country/<<style>>/<<key_name_encoded>>
default: country/<<style>>/<<original_key_name_encoded>>
style:
default: white
translation_key:

@ -41,7 +41,7 @@ dynamic_collections:
filter_term:
default: origin_country
image:
default: country/<<style>>/<<key_name_encoded>>
default: country/<<style>>/<<original_key_name_encoded>>
style:
default: white
translation_key:

@ -1008,8 +1008,13 @@ class CollectionBuilder:
self.item_details[method_name] = str(method_data).lower()
def _radarr(self, method_name, method_data):
if method_name in ["radarr_add_missing", "radarr_add_existing", "radarr_upgrade_existing", "radarr_monitor", "radarr_search"]:
if method_name in ["radarr_add_missing", "radarr_add_existing", "radarr_upgrade_existing", "radarr_search"]:
self.radarr_details[method_name[7:]] = util.parse(self.Type, method_name, method_data, datatype="bool")
elif method_name == "radarr_monitor":
if str(method_data).lower() in radarr.monitor_translation:
self.radarr_details["monitor"] = str(method_data).lower()
else:
raise Failed(f"{self.Type} Error: {method_name} attribute must be either movie, collection, or none")
elif method_name == "radarr_folder":
self.radarr_details["folder"] = method_data
elif method_name == "radarr_availability":
@ -2733,15 +2738,20 @@ class CollectionBuilder:
raise Failed(str(e))
items = self.library.get_filter_items(search_data[2])
previous = None
sort_edit = False
for i, item in enumerate(items, 0):
try:
if len(self.items) <= i or item.ratingKey != self.items[i].ratingKey:
text = f"after {util.item_title(previous)}" if previous else "to the beginning"
self.library.moveItem(self.obj, item, previous)
logger.info(f"Moving {util.item_title(item)} {text}")
sort_edit = True
previous = item
except Failed:
logger.error(f"Failed to Move {util.item_title(item)}")
sort_edit = True
if not sort_edit:
logger.info("No Sorting Required")
def sync_trakt_list(self):
logger.info("")

@ -612,7 +612,7 @@ class ConfigFile:
"add_existing": check_for_attribute(self.data, "add_existing", parent="radarr", var_type="bool", default=False),
"upgrade_existing": check_for_attribute(self.data, "upgrade_existing", parent="radarr", var_type="bool", default=False),
"root_folder_path": check_for_attribute(self.data, "root_folder_path", parent="radarr", default_is_none=True),
"monitor": check_for_attribute(self.data, "monitor", parent="radarr", var_type="bool", default=True),
"monitor": check_for_attribute(self.data, "monitor", parent="radarr", test_list=radarr.monitor_descriptions, default="movie"),
"availability": check_for_attribute(self.data, "availability", parent="radarr", test_list=radarr.availability_descriptions, default="announced"),
"quality_profile": check_for_attribute(self.data, "quality_profile", parent="radarr", default_is_none=True),
"tag": check_for_attribute(self.data, "tag", parent="radarr", var_type="lower_list", default_is_none=True),
@ -880,7 +880,7 @@ class ConfigFile:
"add_existing": check_for_attribute(lib, "add_existing", parent="radarr", var_type="bool", default=self.general["radarr"]["add_existing"], save=False),
"upgrade_existing": check_for_attribute(lib, "upgrade_existing", parent="radarr", var_type="bool", default=self.general["radarr"]["upgrade_existing"], save=False),
"root_folder_path": check_for_attribute(lib, "root_folder_path", parent="radarr", default=self.general["radarr"]["root_folder_path"], req_default=True, save=False),
"monitor": check_for_attribute(lib, "monitor", parent="radarr", var_type="bool", default=self.general["radarr"]["monitor"], save=False),
"monitor": check_for_attribute(lib, "monitor", parent="radarr", test_list=radarr.monitor_descriptions, default=self.general["radarr"]["monitor"], save=False),
"availability": check_for_attribute(lib, "availability", parent="radarr", test_list=radarr.availability_descriptions, default=self.general["radarr"]["availability"], save=False),
"quality_profile": check_for_attribute(lib, "quality_profile", parent="radarr", default=self.general["radarr"]["quality_profile"], req_default=True, save=False),
"tag": check_for_attribute(lib, "tag", parent="radarr", var_type="lower_list", default=self.general["radarr"]["tag"], default_is_none=True, save=False),

@ -932,7 +932,9 @@ class MetadataFile(DataFile):
logger.debug(f"Sync: {sync}")
logger.debug(f"Include: {include}")
logger.debug(f"Other Name: {other_name}")
logger.debug(f"Keys (Title)")
if not auto_list:
raise Failed("No Keys found to create a set of Dynamic Collections")
logger.debug(f"Keys (Title):")
for key, value in auto_list.items():
logger.debug(f" - {key}{'' if key == value else f' ({value})'}")

@ -1,5 +1,5 @@
from modules import util
from modules.util import Failed
from modules.util import Failed, Continue
from arrapi import RadarrAPI
from arrapi.exceptions import ArrException
@ -7,8 +7,10 @@ logger = util.logger
builders = ["radarr_all", "radarr_taglist"]
availability_translation = {"announced": "announced", "cinemas": "inCinemas", "released": "released", "db": "preDB"}
monitor_translation = {"movie": "movieOnly", "collection": "movieAndCollection", "none": "none"}
apply_tags_translation = {"": "add", "sync": "replace", "remove": "remove"}
availability_descriptions = {"announced": "For Announced", "cinemas": "For In Cinemas", "released": "For Released", "db": "For PreDB"}
monitor_descriptions = {"movie": "Monitor Only the Movie", "collection": "Monitor the Movie and Collection", "none": "Do not Monitor"}
class Radarr:
def __init__(self, config, library, params):
@ -53,7 +55,9 @@ class Radarr:
logger.debug(tmdb_id)
upgrade_existing = options["upgrade_existing"] if "upgrade_existing" in options else self.upgrade_existing
folder = options["folder"] if "folder" in options else self.root_folder_path
monitor = options["monitor"] if "monitor" in options else self.monitor
monitor = monitor_translation[options["monitor"] if "monitor" in options else self.monitor]
if not self.api._raw.v4:
monitor = monitor != "none"
availability = availability_translation[options["availability"] if "availability" in options else self.availability]
quality_profile = options["quality"] if "quality" in options else self.quality_profile
tags = options["tag"] if "tag" in options else self.tag
@ -72,33 +76,23 @@ class Radarr:
exists = []
skipped = []
invalid = []
excluded = []
invalid_root = []
movies = []
path_lookup = {}
mismatched = {}
path_in_use = {}
def mass_add():
try:
_a, _e, _i = self.api.add_multiple_movies(movies, folder, quality_profile, monitor, search,
availability, tags, per_request=100)
added.extend(_a)
exists.extend(_e)
invalid.extend(_i)
except ArrException as e:
logger.stacktrace()
raise Failed(f"Radarr Error: {e}")
for i, item in enumerate(tmdb_ids, 1):
path = item[1] if isinstance(item, tuple) else None
tmdb_id = item[0] if isinstance(item, tuple) else item
logger.ghost(f"Loading TMDb ID {i}/{len(tmdb_ids)} ({tmdb_id})")
if self.config.Cache:
_id = self.config.Cache.query_radarr_adds(tmdb_id, self.library.original_mapping_name)
if _id:
skipped.append(item)
continue
try:
if self.config.Cache:
_id = self.config.Cache.query_radarr_adds(tmdb_id, self.library.original_mapping_name)
if _id:
skipped.append(item)
continue
if tmdb_id in arr_ids:
exists.append(arr_ids[tmdb_id])
continue
@ -107,12 +101,12 @@ class Radarr:
continue
if path and not path.startswith(folder):
invalid_root.append(item)
continue
raise Continue
movie = self.api.get_movie(tmdb_id=tmdb_id)
logger.trace(f"Folder to Check: {folder}/{movie.folder}")
if f"{folder}/{movie.folder}".lower() in arr_paths:
path_in_use[f"{folder}/{movie.folder}"] = tmdb_id
continue
raise Continue
if path:
movies.append((movie, path))
path_lookup[path] = tmdb_id
@ -120,12 +114,20 @@ class Radarr:
movies.append(movie)
except ArrException:
invalid.append(item)
if len(movies) == 100 or len(tmdb_ids) == i:
mass_add()
movies = []
if movies:
mass_add()
movies = []
except Continue:
pass
if movies and (len(movies) == 100 or len(tmdb_ids) == i):
try:
_a, _e, _i, _x = self.api.add_multiple_movies(movies, folder, quality_profile, monitor, search,
availability, tags, per_request=100)
added.extend(_a)
exists.extend(_e)
invalid.extend(_i)
excluded.extend(_x)
movies = []
except ArrException as e:
logger.stacktrace()
raise Failed(f"Radarr Error: {e}")
qp = None
for profile in self.profiles:
@ -156,8 +158,8 @@ class Radarr:
for movie in upgrade_qp:
logger.info(f"Quality Upgraded To {qp.name} | {movie.tmdbId:<7} | {movie.title}")
if len(skipped) > 0:
for movie in skipped:
logger.info(f"Skipped: In Cache | {movie}")
logger.info(f"Skipped In Cache: {skipped}")
logger.info("")
logger.info(f"{len(exists) + len(skipped)} Movie{'s' if len(skipped) > 1 else ''} already exist in Radarr")
if len(mismatched) > 0:
@ -165,6 +167,7 @@ class Radarr:
logger.info("Items in Plex that have already been added to Radarr but under a different TMDb ID then in Plex")
for path, tmdb_id in mismatched.items():
logger.info(f"Plex TMDb ID: {tmdb_id:<7} | Radarr TMDb ID: {arr_paths[path.lower()]:<7} | Path: {path}")
logger.info("")
logger.info(f"{len(mismatched)} Movie{'s' if len(mismatched) > 1 else ''} with mismatched TMDb IDs")
if len(path_in_use) > 0:
@ -172,18 +175,26 @@ class Radarr:
logger.info("TMDb IDs that cannot be added to Radarr because the path they will use is already in use by a different TMDb ID")
for path, tmdb_id in path_in_use.items():
logger.info(f"TMDb ID: {tmdb_id:<7} | Radarr TMDb ID: {arr_paths[path.lower()]:<7} | Path: {path}")
logger.info("")
logger.info(f"{len(path_in_use)} Movie{'s' if len(path_in_use) > 1 else ''} with paths already in use by other TMDb IDs")
if len(invalid) > 0:
logger.info("")
for tmdb_id in invalid:
logger.info(f"Invalid TMDb ID | {tmdb_id}")
logger.info(f"Invalid TMDb IDs: {invalid}")
logger.info("")
logger.info(f"{len(invalid)} Movie{'s' if len(invalid) > 1 else ''} with Invalid IDs")
if len(excluded) > 0:
logger.info("")
logger.info(f"Excluded TMDb IDs: {excluded}")
logger.info("")
logger.info(f"{len(excluded)} Movie{'s' if len(excluded) > 1 else ''} ignored by Radarr's Exclusion List")
if len(invalid_root) > 0:
logger.info("")
for tmdb_id, path in invalid_root:
logger.info(f"Invalid Root Folder for TMDb ID | {tmdb_id:<7} | {path}")
logger.info("")
logger.info(f"{len(invalid_root)} Movie{'s' if len(invalid_root) > 1 else ''} with Invalid Paths")
return added

@ -1,5 +1,5 @@
from modules import util
from modules.util import Failed
from modules.util import Failed, Continue
from arrapi import SonarrAPI
from arrapi.exceptions import ArrException
@ -98,47 +98,37 @@ class Sonarr:
exists = []
skipped = []
invalid = []
excluded = []
invalid_root = []
shows = []
path_lookup = {}
mismatched = {}
path_in_use = {}
def mass_add():
try:
_a, _e, _i = self.api.add_multiple_series(shows, folder, quality_profile, language_profile, monitor,
season, search, cutoff_search, series_type, tags, per_request=100)
added.extend(_a)
exists.extend(_e)
invalid.extend(_i)
except ArrException as e:
logger.stacktrace()
raise Failed(f"Sonarr Error: {e}")
for i, item in enumerate(tvdb_ids, 1):
path = item[1] if isinstance(item, tuple) else None
tvdb_id = item[0] if isinstance(item, tuple) else item
logger.ghost(f"Loading TVDb ID {i}/{len(tvdb_ids)} ({tvdb_id})")
if self.config.Cache:
_id = self.config.Cache.query_sonarr_adds(tvdb_id, self.library.original_mapping_name)
if _id:
skipped.append(item)
continue
try:
if self.config.Cache:
_id = self.config.Cache.query_sonarr_adds(tvdb_id, self.library.original_mapping_name)
if _id:
skipped.append(item)
raise Continue
if tvdb_id in arr_ids:
exists.append(arr_ids[tvdb_id])
continue
raise Continue
if path and path.lower() in arr_paths:
mismatched[path] = tvdb_id
continue
raise Continue
if path and not path.startswith(folder):
invalid_root.append(item)
continue
raise Continue
show = self.api.get_series(tvdb_id=tvdb_id)
logger.trace(f"Folder to Check: {folder}/{show.folder}")
if f"{folder}/{show.folder}".lower() in arr_paths:
path_in_use[f"{folder}/{show.folder}"] = tvdb_id
continue
raise Continue
if path:
shows.append((show, path))
path_lookup[path] = tvdb_id
@ -146,12 +136,20 @@ class Sonarr:
shows.append(show)
except ArrException:
invalid.append(item)
if len(shows) == 100 or len(tvdb_ids) == i:
mass_add()
shows = []
if shows:
mass_add()
shows = []
except Continue:
pass
if shows and (len(shows) == 100 or len(tvdb_ids) == i):
try:
_a, _e, _i, _x = self.api.add_multiple_series(shows, folder, quality_profile, language_profile, monitor,
season, search, cutoff_search, series_type, tags, per_request=100)
added.extend(_a)
exists.extend(_e)
invalid.extend(_i)
excluded.extend(_x)
shows = []
except ArrException as e:
logger.stacktrace()
raise Failed(f"Sonarr Error: {e}")
qp = None
for profile in self.profiles:
@ -182,8 +180,8 @@ class Sonarr:
for series in upgrade_qp:
logger.info(f"Quality Upgraded To {qp.name} | {series.tvdbId:<7} | {series.title}")
if len(skipped) > 0:
for series in skipped:
logger.info(f"Skipped: In Cache | {series}")
logger.info(f"Skipped In Cache: {skipped}")
logger.info("")
logger.info(f"{len(exists) + len(skipped)} Series already exist in Sonarr")
if len(mismatched) > 0:
@ -191,6 +189,7 @@ class Sonarr:
logger.info("Items in Plex that have already been added to Sonarr but under a different TVDb ID then in Plex")
for path, tmdb_id in mismatched.items():
logger.info(f"Plex TVDb ID: {tmdb_id:<7} | Sonarr TVDb ID: {arr_paths[path.lower()]:<7} | Path: {path}")
logger.info("")
logger.info(f"{len(mismatched)} Series with mismatched TVDb IDs")
if len(path_in_use) > 0:
@ -198,18 +197,26 @@ class Sonarr:
logger.info("TVDb IDs that cannot be added to Sonarr because the path they will use is already in use by a different TVDb ID")
for path, tvdb_id in path_in_use.items():
logger.info(f"TVDb ID: {tvdb_id:<7} | Sonarr TVDb ID: {arr_paths[path.lower()]:<7} | Path: {path}")
logger.info("")
logger.info(f"{len(path_in_use)} Series with paths already in use by other TVDb IDs")
if len(invalid) > 0:
for tvdb_id in invalid:
logger.info("")
logger.info(f"Invalid TVDb ID | {tvdb_id}")
logger.info("")
logger.info(f"Invalid TVDb IDs: {invalid}")
logger.info("")
logger.info(f"{len(invalid)} Series with Invalid IDs")
if len(excluded) > 0:
logger.info("")
logger.info(f"Excluded TVDb IDs: {excluded}")
logger.info("")
logger.info(f"{len(excluded)} Series ignored by Sonarr's Exclusion List")
if len(invalid_root) > 0:
logger.info("")
for tvdb_id, path in invalid_root:
logger.info(f"Invalid Root Folder for TVDb ID | {tvdb_id:<7} | {path}")
logger.info("")
logger.info(f"{len(invalid_root)} Series with Invalid Paths")
return added

@ -28,6 +28,9 @@ class Failed(Exception):
class FilterFailed(Failed):
pass
class Continue(Exception):
pass
class Deleted(Exception):
pass

@ -1,6 +1,6 @@
PlexAPI==4.13.1
tmdbapis==1.0.8
arrapi==1.3.1
arrapi==1.4.0
lxml==4.9.1
requests==2.28.1
requests-cache==0.9.6

Loading…
Cancel
Save