changed dictionary operations

pull/138/head
meisnate12 4 years ago
parent 1b59adf541
commit eeb2320f62

@ -86,9 +86,9 @@ class CollectionBuilder:
else: else:
raise Failed("Collection Error: template sub-attribute optional is blank") raise Failed("Collection Error: template sub-attribute optional is blank")
for m in template: for method_name, attr_data in template:
if m not in self.data and m not in ["default", "optional"]: if method_name not in self.data and method_name not in ["default", "optional"]:
if template[m]: if attr_data:
def replace_txt(txt): def replace_txt(txt):
txt = str(txt) txt = str(txt)
for option in optional: for option in optional:
@ -108,33 +108,33 @@ class CollectionBuilder:
try: return int(txt) try: return int(txt)
except ValueError: return txt except ValueError: return txt
try: try:
if isinstance(template[m], dict): if isinstance(attr_data, dict):
a = {} discover_name = {}
for sm in template[m]: for sm in attr_data:
if isinstance(template[m][sm], list): if isinstance(attr_data[sm], list):
temp_list = [] temp_list = []
for li in template[m][sm]: for li in attr_data[sm]:
temp_list.append(replace_txt(li)) temp_list.append(replace_txt(li))
a[sm] = temp_list discover_name[sm] = temp_list
else: else:
a[sm] = replace_txt(template[m][sm]) discover_name[sm] = replace_txt(attr_data[sm])
elif isinstance(template[m], list): elif isinstance(attr_data, list):
a = [] discover_name = []
for li in template[m]: for li in attr_data:
if isinstance(li, dict): if isinstance(li, dict):
temp_dict = {} temp_dict = {}
for sm in li: for sm in li:
temp_dict[sm] = replace_txt(li[sm]) temp_dict[sm] = replace_txt(li[sm])
a.append(temp_dict) discover_name.append(temp_dict)
else: else:
a.append(replace_txt(li)) discover_name.append(replace_txt(li))
else: else:
a = replace_txt(template[m]) discover_name = replace_txt(attr_data)
except Failed: except Failed:
continue continue
self.data[m] = a self.data[method_name] = discover_name
else: else:
raise Failed(f"Collection Error: template attribute {m} is blank") raise Failed(f"Collection Error: template attribute {method_name} is blank")
skip_collection = True skip_collection = True
if "schedule" not in methods: if "schedule" not in methods:
@ -211,21 +211,21 @@ class CollectionBuilder:
else: else:
raise Failed("Collection Error: tmdb_person attribute is blank") raise Failed("Collection Error: tmdb_person attribute is blank")
for m in self.data: for method_name, method_data in self.data.items():
if "tmdb" in m.lower() and not config.TMDb: raise Failed(f"Collection Error: {m} requires TMDb to be configured") if "tmdb" in method_name.lower() and not config.TMDb: raise Failed(f"Collection Error: {method_name} requires TMDb to be configured")
elif "trakt" in m.lower() and not config.Trakt: raise Failed(f"Collection Error: {m} requires Trakt todo be configured") elif "trakt" in method_name.lower() and not config.Trakt: raise Failed(f"Collection Error: {method_name} requires Trakt todo be configured")
elif "imdb" in m.lower() and not config.IMDb: raise Failed(f"Collection Error: {m} requires TMDb or Trakt to 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 "tautulli" in m.lower() and not self.library.Tautulli: raise Failed(f"Collection Error: {m} requires Tautulli 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 "mal" in m.lower() and not config.MyAnimeList: raise Failed(f"Collection Error: {m} requires MyAnimeList 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 self.data[m] is not None: elif method_data is not None:
logger.debug("") logger.debug("")
logger.debug(f"Method: {m}") logger.debug(f"Method: {method_name}")
logger.debug(f"Value: {self.data[m]}") logger.debug(f"Value: {method_data}")
if m.lower() in util.method_alias: if method_name.lower() in util.method_alias:
method_name = util.method_alias[m.lower()] method_name = util.method_alias[method_name.lower()]
logger.warning(f"Collection Warning: {m} attribute will run as {method_name}") logger.warning(f"Collection Warning: {method_name} attribute will run as {method_name}")
else: else:
method_name = m.lower() method_name = method_name.lower()
if method_name in util.show_only_lists and self.library.is_movie: if method_name in util.show_only_lists 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 util.movie_only_lists and self.library.is_show: elif method_name in util.movie_only_lists and self.library.is_show:
@ -235,76 +235,76 @@ class CollectionBuilder:
elif method_name not in util.collectionless_lists and self.collectionless: elif method_name not in util.collectionless_lists and self.collectionless:
raise Failed(f"Collection Error: {method_name} attribute does not work for Collectionless collection") raise Failed(f"Collection Error: {method_name} attribute does not work for Collectionless collection")
elif method_name == "summary": elif method_name == "summary":
self.summaries[method_name] = self.data[m] self.summaries[method_name] = method_data
elif method_name == "tmdb_summary": elif method_name == "tmdb_summary":
self.summaries[method_name] = config.TMDb.get_movie_show_or_collection(util.regex_first_int(self.data[m], "TMDb ID"), self.library.is_movie).overview self.summaries[method_name] = config.TMDb.get_movie_show_or_collection(util.regex_first_int(method_data, "TMDb ID"), self.library.is_movie).overview
elif method_name == "tmdb_description": elif method_name == "tmdb_description":
self.summaries[method_name] = config.TMDb.get_list(util.regex_first_int(self.data[m], "TMDb List ID")).description self.summaries[method_name] = config.TMDb.get_list(util.regex_first_int(method_data, "TMDb List ID")).description
elif method_name == "tmdb_biography": elif method_name == "tmdb_biography":
self.summaries[method_name] = config.TMDb.get_person(util.regex_first_int(self.data[m], "TMDb Person ID")).biography self.summaries[method_name] = config.TMDb.get_person(util.regex_first_int(method_data, "TMDb Person ID")).biography
elif method_name == "tvdb_summary": elif method_name == "tvdb_summary":
self.summaries[method_name] = config.TVDb.get_movie_or_show(self.data[m], self.library.Plex.language, self.library.is_movie).summary self.summaries[method_name] = config.TVDb.get_movie_or_show(method_data, self.library.Plex.language, self.library.is_movie).summary
elif method_name == "tvdb_description": elif method_name == "tvdb_description":
self.summaries[method_name] = config.TVDb.get_list_description(self.data[m], self.library.Plex.language) self.summaries[method_name] = config.TVDb.get_list_description(method_data, self.library.Plex.language)
elif method_name == "trakt_description": elif method_name == "trakt_description":
self.summaries[method_name] = config.Trakt.standard_list(config.Trakt.validate_trakt_list(util.get_list(self.data[m]))[0]).description self.summaries[method_name] = config.Trakt.standard_list(config.Trakt.validate_trakt_list(util.get_list(method_data))[0]).description
elif method_name == "letterboxd_description": elif method_name == "letterboxd_description":
self.summaries[method_name] = config.Letterboxd.get_list_description(self.data[m], self.library.Plex.language) self.summaries[method_name] = config.Letterboxd.get_list_description(method_data, self.library.Plex.language)
elif method_name == "collection_mode": elif method_name == "collection_mode":
if str(self.data[m]).lower() == "default": if str(method_data).lower() == "default":
self.details[method_name] = "default" self.details[method_name] = "default"
elif str(self.data[m]).lower() == "hide": elif str(method_data).lower() == "hide":
self.details[method_name] = "hide" self.details[method_name] = "hide"
elif str(self.data[m]).lower() in ["hide_items", "hideitems"]: elif str(method_data).lower() in ["hide_items", "hideitems"]:
self.details[method_name] = "hideItems" self.details[method_name] = "hideItems"
elif str(self.data[m]).lower() in ["show_items", "showitems"]: elif str(method_data).lower() in ["show_items", "showitems"]:
self.details[method_name] = "showItems" self.details[method_name] = "showItems"
else: else:
raise Failed(f"Collection Error: {self.data[m]} collection_mode invalid\n\tdefault (Library default)\n\thide (Hide Collection)\n\thide_items (Hide Items in this Collection)\n\tshow_items (Show this Collection and its Items)") raise Failed(f"Collection Error: {method_data} collection_mode invalid\n\tdefault (Library default)\n\thide (Hide Collection)\n\thide_items (Hide Items in this Collection)\n\tshow_items (Show this Collection and its Items)")
elif method_name == "collection_order": elif method_name == "collection_order":
if str(self.data[m]).lower() == "release": if str(method_data).lower() == "release":
self.details[method_name] = "release" self.details[method_name] = "release"
elif str(self.data[m]).lower() == "alpha": elif str(method_data).lower() == "alpha":
self.details[method_name] = "release" self.details[method_name] = "release"
else: else:
raise Failed(f"Collection Error: {self.data[m]} collection_order invalid\n\trelease (Order Collection by release dates)\n\talpha (Order Collection Alphabetically)") raise Failed(f"Collection Error: {method_data} collection_order invalid\n\trelease (Order Collection by release dates)\n\talpha (Order Collection Alphabetically)")
elif method_name == "url_poster": elif method_name == "url_poster":
self.posters[method_name] = self.data[m] self.posters[method_name] = method_data
elif method_name == "tmdb_poster": elif method_name == "tmdb_poster":
self.posters[method_name] = f"{config.TMDb.image_url}{config.TMDb.get_movie_show_or_collection(util.regex_first_int(self.data[m], 'TMDb ID'), self.library.is_movie).poster_path}" self.posters[method_name] = f"{config.TMDb.image_url}{config.TMDb.get_movie_show_or_collection(util.regex_first_int(method_data, 'TMDb ID'), self.library.is_movie).poster_path}"
elif method_name == "tmdb_profile": elif method_name == "tmdb_profile":
self.posters[method_name] = f"{config.TMDb.image_url}{config.TMDb.get_person(util.regex_first_int(self.data[m], 'TMDb Person ID')).profile_path}" self.posters[method_name] = f"{config.TMDb.image_url}{config.TMDb.get_person(util.regex_first_int(method_data, 'TMDb Person ID')).profile_path}"
elif method_name == "tvdb_poster": elif method_name == "tvdb_poster":
self.posters[method_name] = f"{config.TVDb.get_movie_or_series(self.data[m], self.library.Plex.language, self.library.is_movie).poster_path}" self.posters[method_name] = f"{config.TVDb.get_movie_or_series(method_data, self.library.Plex.language, self.library.is_movie).poster_path}"
elif method_name == "file_poster": elif method_name == "file_poster":
if os.path.exists(self.data[m]): if os.path.exists(method_data):
self.posters[method_name] = os.path.abspath(self.data[m]) self.posters[method_name] = os.path.abspath(method_data)
else: else:
raise Failed(f"Collection Error: Poster Path Does Not Exist: {os.path.abspath(self.data[m])}") raise Failed(f"Collection Error: Poster Path Does Not Exist: {os.path.abspath(method_data)}")
elif method_name == "url_background": elif method_name == "url_background":
self.backgrounds[method_name] = self.data[m] self.backgrounds[method_name] = method_data
elif method_name == "tmdb_background": elif method_name == "tmdb_background":
self.backgrounds[method_name] = f"{config.TMDb.image_url}{config.TMDb.get_movie_show_or_collection(util.regex_first_int(self.data[m], 'TMDb ID'), self.library.is_movie).poster_path}" self.backgrounds[method_name] = f"{config.TMDb.image_url}{config.TMDb.get_movie_show_or_collection(util.regex_first_int(method_data, 'TMDb ID'), self.library.is_movie).poster_path}"
elif method_name == "tvdb_background": elif method_name == "tvdb_background":
self.posters[method_name] = f"{config.TVDb.get_movie_or_series(self.data[m], self.library.Plex.language, self.library.is_movie).background_path}" self.posters[method_name] = f"{config.TVDb.get_movie_or_series(method_data, self.library.Plex.language, self.library.is_movie).background_path}"
elif method_name == "file_background": elif method_name == "file_background":
if os.path.exists(self.data[m]): self.backgrounds[method_name] = os.path.abspath(self.data[m]) if os.path.exists(method_data): self.backgrounds[method_name] = os.path.abspath(method_data)
else: raise Failed(f"Collection Error: Background Path Does Not Exist: {os.path.abspath(self.data[m])}") else: raise Failed(f"Collection Error: Background Path Does Not Exist: {os.path.abspath(method_data)}")
elif method_name == "label_sync_mode": elif method_name == "label_sync_mode":
if self.data[m].lower() in ["append", "sync"]: self.details[method_name] = self.data[m].lower() if str(method_data).lower() in ["append", "sync"]: self.details[method_name] = method_data.lower()
else: raise Failed("Collection Error: label_sync_mode attribute must be either 'append' or 'sync'") else: raise Failed("Collection Error: label_sync_mode attribute must be either 'append' or 'sync'")
elif method_name == "sync_mode": elif method_name == "sync_mode":
if self.data[m].lower() in ["append", "sync"]: self.details[method_name] = self.data[m].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 in ["arr_tag", "label"]:
self.details[method_name] = util.get_list(self.data[m]) self.details[method_name] = util.get_list(method_data)
elif method_name in util.boolean_details: elif method_name in util.boolean_details:
if isinstance(self.data[m], bool): self.details[method_name] = self.data[m] if isinstance(method_data, bool): self.details[method_name] = method_data
elif str(self.data[m]).lower() in ["t", "true"]: self.details[method_name] = True elif str(method_data).lower() in ["t", "true"]: self.details[method_name] = True
elif str(self.data[m]).lower() in ["f", "false"]: self.details[method_name] = False elif str(method_data).lower() in ["f", "false"]: self.details[method_name] = False
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 util.all_details: elif method_name in util.all_details:
self.details[method_name] = self.data[m] self.details[method_name] = method_data
elif method_name in ["year", "year.not"]: elif method_name in ["year", "year.not"]:
self.methods.append(("plex_search", [[(method_name, util.get_year_list(self.data[m], method_name))]])) self.methods.append(("plex_search", [[(method_name, util.get_year_list(self.data[m], method_name))]]))
elif method_name in ["decade", "decade.not"]: elif method_name in ["decade", "decade.not"]:
@ -325,33 +325,33 @@ class CollectionBuilder:
elif method_name == "plex_all": elif method_name == "plex_all":
self.methods.append((method_name, [""])) self.methods.append((method_name, [""]))
elif method_name == "plex_collection": elif method_name == "plex_collection":
self.methods.append((method_name, self.library.validate_collections(self.data[m] if isinstance(self.data[m], list) else [self.data[m]]))) self.methods.append((method_name, self.library.validate_collections(method_data if isinstance(method_data, list) else [method_data])))
elif method_name == "anidb_popular": elif method_name == "anidb_popular":
list_count = util.regex_first_int(self.data[m], "List Size", default=40) list_count = util.regex_first_int(method_data, "List Size", default=40)
if 1 <= list_count <= 30: if 1 <= list_count <= 30:
self.methods.append((method_name, [list_count])) self.methods.append((method_name, [list_count]))
else: else:
logger.warning("Collection Error: anidb_popular must be an integer between 1 and 30 defaulting to 30") logger.warning("Collection Error: anidb_popular must be an integer between 1 and 30 defaulting to 30")
self.methods.append((method_name, [30])) self.methods.append((method_name, [30]))
elif method_name == "mal_id": elif method_name == "mal_id":
self.methods.append((method_name, util.get_int_list(self.data[m], "MyAnimeList ID"))) self.methods.append((method_name, util.get_int_list(method_data, "MyAnimeList ID")))
elif method_name in ["anidb_id", "anidb_relation"]: elif method_name in ["anidb_id", "anidb_relation"]:
self.methods.append((method_name, config.AniDB.validate_anidb_list(util.get_int_list(self.data[m], "AniDB ID"), self.library.Plex.language))) self.methods.append((method_name, config.AniDB.validate_anidb_list(util.get_int_list(method_data, "AniDB ID"), self.library.Plex.language)))
elif method_name in ["anilist_id", "anilist_relations", "anilist_studio"]: elif method_name in ["anilist_id", "anilist_relations", "anilist_studio"]:
self.methods.append((method_name, config.AniList.validate_anilist_ids(util.get_int_list(self.data[m], "AniList ID"), studio=method_name == "anilist_studio"))) self.methods.append((method_name, config.AniList.validate_anilist_ids(util.get_int_list(method_data, "AniList ID"), studio=method_name == "anilist_studio")))
elif method_name == "trakt_list": elif method_name == "trakt_list":
self.methods.append((method_name, config.Trakt.validate_trakt_list(util.get_list(self.data[m])))) self.methods.append((method_name, config.Trakt.validate_trakt_list(util.get_list(method_data))))
elif method_name == "trakt_list_details": elif method_name == "trakt_list_details":
valid_list = config.Trakt.validate_trakt_list(util.get_list(self.data[m])) valid_list = config.Trakt.validate_trakt_list(util.get_list(method_data))
item = config.Trakt.standard_list(valid_list[0]) item = config.Trakt.standard_list(valid_list[0])
if hasattr(item, "description") and item.description: if hasattr(item, "description") and item.description:
self.summaries[method_name] = item.description self.summaries[method_name] = item.description
self.methods.append((method_name[:-8], valid_list)) self.methods.append((method_name[:-8], valid_list))
elif method_name == "trakt_watchlist": elif method_name == "trakt_watchlist":
self.methods.append((method_name, config.Trakt.validate_trakt_watchlist(util.get_list(self.data[m]), self.library.is_movie))) self.methods.append((method_name, config.Trakt.validate_trakt_watchlist(util.get_list(method_data), self.library.is_movie)))
elif method_name == "imdb_list": elif method_name == "imdb_list":
new_list = [] new_list = []
for imdb_list in util.get_list(self.data[m], split=False): for imdb_list in util.get_list(method_data, split=False):
if isinstance(imdb_list, dict): if isinstance(imdb_list, dict):
dict_methods = {dm.lower(): dm for dm in imdb_list} dict_methods = {dm.lower(): dm for dm in imdb_list}
if "url" in dict_methods and imdb_list[dict_methods["url"]]: if "url" in dict_methods and imdb_list[dict_methods["url"]]:
@ -365,13 +365,13 @@ class CollectionBuilder:
new_list.append({"url": imdb_url, "limit": list_count}) new_list.append({"url": imdb_url, "limit": list_count})
self.methods.append((method_name, new_list)) self.methods.append((method_name, new_list))
elif method_name == "letterboxd_list": elif method_name == "letterboxd_list":
self.methods.append((method_name, util.get_list(self.data[m], split=False))) self.methods.append((method_name, util.get_list(method_data, split=False)))
elif method_name == "letterboxd_list_details": elif method_name == "letterboxd_list_details":
values = util.get_list(self.data[m], split=False) values = util.get_list(method_data, split=False)
self.summaries[method_name] = config.Letterboxd.get_list_description(values[0], self.library.Plex.language) self.summaries[method_name] = config.Letterboxd.get_list_description(values[0], self.library.Plex.language)
self.methods.append((method_name[:-8], values)) self.methods.append((method_name[:-8], values))
elif method_name in util.dictionary_lists: elif method_name in util.dictionary_lists:
if isinstance(self.data[m], dict): if isinstance(method_data, dict):
def get_int(parent, method, data_in, methods_in, default_in, minimum=1, maximum=None): def get_int(parent, method, data_in, methods_in, default_in, minimum=1, maximum=None):
if method not in methods_in: if method not in methods_in:
logger.warning(f"Collection Warning: {parent} {methods_in[method]} attribute not found using {default_in} as default") logger.warning(f"Collection Warning: {parent} {methods_in[method]} attribute not found using {default_in} as default")
@ -386,50 +386,50 @@ class CollectionBuilder:
logger.warning(f"Collection Warning: {parent} {methods_in[method]} attribute {data_in[methods_in[method]]} invalid must an integer >= {minimum} using {default_in} as default") logger.warning(f"Collection Warning: {parent} {methods_in[method]} attribute {data_in[methods_in[method]]} invalid must an integer >= {minimum} using {default_in} as default")
return default_in return default_in
if method_name == "filters": if method_name == "filters":
for f in self.data[m]: for filter_name, filter_data in method_data.items():
if f.lower() in util.method_alias or (f.lower().endswith(".not") and f.lower()[:-4] in util.method_alias): if filter_name.lower() in util.method_alias or (filter_name.lower().endswith(".not") and filter_name.lower()[:-4] in util.method_alias):
filter_method = (util.method_alias[f.lower()[:-4]] + f.lower()[-4:]) if f.lower().endswith(".not") else util.method_alias[f.lower()] filter_method = (util.method_alias[filter_name.lower()[:-4]] + filter_name.lower()[-4:]) if filter_name.lower().endswith(".not") else util.method_alias[filter_name.lower()]
logger.warning(f"Collection Warning: {f} filter will run as {filter_method}") logger.warning(f"Collection Warning: {filter_name} filter will run as {filter_method}")
else: else:
filter_method = f.lower() filter_method = filter_name.lower()
if filter_method in util.movie_only_filters and self.library.is_show: if filter_method in util.movie_only_filters and self.library.is_show:
raise Failed(f"Collection Error: {filter_method} filter only works for movie libraries") raise Failed(f"Collection Error: {filter_method} filter only works for movie libraries")
elif self.data[m][f] is None: elif filter_data is None:
raise Failed(f"Collection Error: {filter_method} filter is blank") raise Failed(f"Collection Error: {filter_method} filter is blank")
elif filter_method == "year": elif filter_method == "year":
filter_data = util.get_year_list(self.data[m][f], f"{filter_method} filter") valid_data = util.get_year_list(filter_data, current_year, f"{filter_method} filter")
elif filter_method in ["max_age", "duration.gte", "duration.lte", "tmdb_vote_count.gte", "tmdb_vote_count.lte"]: elif filter_method in ["max_age", "duration.gte", "duration.lte", "tmdb_vote_count.gte", "tmdb_vote_count.lte"]:
filter_data = util.check_number(self.data[m][f], f"{filter_method} filter", minimum=1) valid_data = util.check_number(filter_data, f"{filter_method} filter", minimum=1)
elif filter_method in ["year.gte", "year.lte"]: elif filter_method in ["year.gte", "year.lte"]:
filter_data = util.check_number(self.data[m][f], f"{filter_method} filter", minimum=1800, maximum=current_year) valid_data = util.check_year(filter_data, current_year, f"{filter_method} filter")
elif filter_method in ["rating.gte", "rating.lte"]: elif filter_method in ["rating.gte", "rating.lte"]:
filter_data = util.check_number(self.data[m][f], f"{filter_method} filter", number_type="float", minimum=0.1, maximum=10) valid_data = util.check_number(filter_data, f"{filter_method} filter", number_type="float", minimum=0.1, maximum=10)
elif filter_method in ["originally_available.gte", "originally_available.lte"]: elif filter_method in ["originally_available.gte", "originally_available.lte"]:
filter_data = util.check_date(self.data[m][f], f"{filter_method} filter") valid_data = util.check_date(filter_data, f"{filter_method} filter")
elif filter_method == "original_language": elif filter_method == "original_language":
filter_data = util.get_list(self.data[m][f], lower=True) valid_data = util.get_list(filter_data, lower=True)
elif filter_method == "collection": elif filter_method == "collection":
filter_data = self.data[m][f] if isinstance(self.data[m][f], list) else [self.data[m][f]] valid_data = filter_data if isinstance(filter_data, list) else [filter_data]
elif filter_method in util.all_filters: elif filter_method in util.all_filters:
filter_data = util.get_list(self.data[m][f]) valid_data = util.get_list(filter_data)
else: else:
raise Failed(f"Collection Error: {filter_method} filter not supported") raise Failed(f"Collection Error: {filter_method} filter not supported")
self.filters.append((filter_method, filter_data)) self.filters.append((filter_method, valid_data))
elif method_name == "plex_collectionless": elif method_name == "plex_collectionless":
new_dictionary = {} new_dictionary = {}
dict_methods = {dm.lower(): dm for dm in self.data[m]} dict_methods = {dm.lower(): dm for dm in method_data}
prefix_list = [] prefix_list = []
if "exclude_prefix" in dict_methods and self.data[m][dict_methods["exclude_prefix"]]: if "exclude_prefix" in dict_methods and method_data[dict_methods["exclude_prefix"]]:
if isinstance(self.data[m][dict_methods["exclude_prefix"]], list): if isinstance(method_data[dict_methods["exclude_prefix"]], list):
prefix_list.extend(self.data[m][dict_methods["exclude_prefix"]]) prefix_list.extend(method_data[dict_methods["exclude_prefix"]])
else: else:
prefix_list.append(str(self.data[m][dict_methods["exclude_prefix"]])) prefix_list.append(str(method_data[dict_methods["exclude_prefix"]]))
exact_list = [] exact_list = []
if "exclude" in dict_methods and self.data[m][dict_methods["exclude"]]: if "exclude" in dict_methods and method_data[dict_methods["exclude"]]:
if isinstance(self.data[m][dict_methods["exclude"]], list): if isinstance(method_data[dict_methods["exclude"]], list):
exact_list.extend(self.data[m][dict_methods["exclude"]]) exact_list.extend(method_data[dict_methods["exclude"]])
else: else:
exact_list.append(str(self.data[m][dict_methods["exclude"]])) exact_list.append(str(method_data[dict_methods["exclude"]]))
if len(prefix_list) == 0 and len(exact_list) == 0: if len(prefix_list) == 0 and len(exact_list) == 0:
raise Failed("Collection Error: you must have at least one exclusion") raise Failed("Collection Error: you must have at least one exclusion")
new_dictionary["exclude_prefix"] = prefix_list new_dictionary["exclude_prefix"] = prefix_list
@ -464,61 +464,61 @@ class CollectionBuilder:
self.methods.append((method_name, [searches])) self.methods.append((method_name, [searches]))
elif method_name == "tmdb_discover": elif method_name == "tmdb_discover":
new_dictionary = {"limit": 100} new_dictionary = {"limit": 100}
for a in self.data[m]: for discover_name, discover_data in method_data:
a_name = a.lower() discover_final = discover_name.lower()
if self.data[m][a]: if discover_data:
if (self.library.is_movie and a_name in util.discover_movie) or (self.library.is_show and a_name in util.discover_tv): if (self.library.is_movie and discover_final in util.discover_movie) or (self.library.is_show and discover_final in util.discover_tv):
if a_name == "language": if discover_final == "language":
if re.compile("([a-z]{2})-([A-Z]{2})").match(str(self.data[m][a])): if re.compile("([a-z]{2})-([A-Z]{2})").match(str(discover_data)):
new_dictionary[a_name] = str(self.data[m][a]) new_dictionary[discover_final] = str(discover_data)
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name}: {self.data[m][a]} must match pattern ([a-z]{{2}})-([A-Z]{{2}}) e.g. en-US") raise Failed(f"Collection Error: {method_name} attribute {discover_final}: {discover_data} must match pattern ([a-z]{{2}})-([A-Z]{{2}}) e.g. en-US")
elif a_name == "region": elif discover_final == "region":
if re.compile("^[A-Z]{2}$").match(str(self.data[m][a])): if re.compile("^[A-Z]{2}$").match(str(discover_data)):
new_dictionary[a_name] = str(self.data[m][a]) new_dictionary[discover_final] = str(discover_data)
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name}: {self.data[m][a]} must match pattern ^[A-Z]{{2}}$ e.g. US") raise Failed(f"Collection Error: {method_name} attribute {discover_final}: {discover_data} must match pattern ^[A-Z]{{2}}$ e.g. US")
elif a_name == "sort_by": elif discover_final == "sort_by":
if (self.library.is_movie and self.data[m][a] in util.discover_movie_sort) or (self.library.is_show and self.data[m][a] in util.discover_tv_sort): if (self.library.is_movie and discover_data in util.discover_movie_sort) or (self.library.is_show and discover_data in util.discover_tv_sort):
new_dictionary[a_name] = self.data[m][a] new_dictionary[discover_final] = discover_data
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name}: {self.data[m][a]} is invalid") raise Failed(f"Collection Error: {method_name} attribute {discover_final}: {discover_data} is invalid")
elif a_name == "certification_country": elif discover_final == "certification_country":
if "certification" in self.data[m] or "certification.lte" in self.data[m] or "certification.gte" in self.data[m]: if "certification" in method_data or "certification.lte" in method_data or "certification.gte" in method_data:
new_dictionary[a_name] = self.data[m][a] new_dictionary[discover_final] = discover_data
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name}: must be used with either certification, certification.lte, or certification.gte") raise Failed(f"Collection Error: {method_name} attribute {discover_final}: must be used with either certification, certification.lte, or certification.gte")
elif a_name in ["certification", "certification.lte", "certification.gte"]: elif discover_final in ["certification", "certification.lte", "certification.gte"]:
if "certification_country" in self.data[m]: if "certification_country" in method_data:
new_dictionary[a_name] = self.data[m][a] new_dictionary[discover_final] = discover_data
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name}: must be used with certification_country") raise Failed(f"Collection Error: {method_name} attribute {discover_final}: must be used with certification_country")
elif a_name in ["include_adult", "include_null_first_air_dates", "screened_theatrically"]: elif discover_final in ["include_adult", "include_null_first_air_dates", "screened_theatrically"]:
if self.data[m][a] is True: if discover_data is True:
new_dictionary[a_name] = self.data[m][a] new_dictionary[discover_final] = discover_data
elif a_name in util.discover_dates: elif discover_final in util.discover_dates:
new_dictionary[a_name] = util.check_date(self.data[m][a], f"{m} attribute {a_name}", return_string=True) new_dictionary[discover_final] = util.check_date(discover_data, f"{method_name} attribute {discover_final}", return_string=True)
elif a_name in ["primary_release_year", "year", "first_air_date_year"]: elif discover_final in ["primary_release_year", "year", "first_air_date_year"]:
new_dictionary[a_name] = util.check_number(self.data[m][a], f"{m} attribute {a_name}", minimum=1800, maximum=current_year + 1) new_dictionary[discover_final] = util.check_number(discover_data, f"{method_name} attribute {discover_final}", minimum=1800, maximum=current_year + 1)
elif a_name in ["vote_count.gte", "vote_count.lte", "vote_average.gte", "vote_average.lte", "with_runtime.gte", "with_runtime.lte"]: elif discover_final in ["vote_count.gte", "vote_count.lte", "vote_average.gte", "vote_average.lte", "with_runtime.gte", "with_runtime.lte"]:
new_dictionary[a_name] = util.check_number(self.data[m][a], f"{m} attribute {a_name}", minimum=1) new_dictionary[discover_final] = util.check_number(discover_data, f"{method_name} attribute {discover_final}", minimum=1)
elif a_name in ["with_cast", "with_crew", "with_people", "with_companies", "with_networks", "with_genres", "without_genres", "with_keywords", "without_keywords", "with_original_language", "timezone"]: elif discover_final in ["with_cast", "with_crew", "with_people", "with_companies", "with_networks", "with_genres", "without_genres", "with_keywords", "without_keywords", "with_original_language", "timezone"]:
new_dictionary[a_name] = self.data[m][a] new_dictionary[discover_final] = discover_data
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name} not supported") raise Failed(f"Collection Error: {method_name} attribute {discover_final} not supported")
elif a_name == "limit": elif discover_final == "limit":
if isinstance(self.data[m][a], int) and self.data[m][a] > 0: if isinstance(discover_data, int) and discover_data > 0:
new_dictionary[a_name] = self.data[m][a] new_dictionary[discover_final] = discover_data
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name}: must be a valid number greater then 0") raise Failed(f"Collection Error: {method_name} attribute {discover_final}: must be a valid number greater then 0")
else: else:
raise Failed(f"Collection Error: {m} attribute {a_name} not supported") raise Failed(f"Collection Error: {method_name} attribute {discover_final} not supported")
else: else:
raise Failed(f"Collection Error: {m} parameter {a_name} is blank") raise Failed(f"Collection Error: {method_name} parameter {discover_final} is blank")
if len(new_dictionary) > 1: if len(new_dictionary) > 1:
self.methods.append((method_name, [new_dictionary])) self.methods.append((method_name, [new_dictionary]))
else: else:
raise Failed(f"Collection Error: {m} had no valid fields") raise Failed(f"Collection Error: {method_name} had no valid fields")
elif "tautulli" in method_name: elif "tautulli" in method_name:
new_dictionary = {} new_dictionary = {}
if method_name == "tautulli_popular": if method_name == "tautulli_popular":
@ -527,22 +527,22 @@ class CollectionBuilder:
new_dictionary["list_type"] = "watched" new_dictionary["list_type"] = "watched"
else: else:
raise Failed(f"Collection Error: {method_name} attribute not supported") raise Failed(f"Collection Error: {method_name} attribute not supported")
dict_methods = {dm.lower(): dm for dm in self.data[m]} dict_methods = {dm.lower(): dm for dm in method_data}
new_dictionary["list_days"] = get_int(method_name, "list_days", self.data[m], dict_methods, 30) new_dictionary["list_days"] = get_int(method_name, "list_days", method_data, dict_methods, 30)
new_dictionary["list_size"] = get_int(method_name, "list_size", self.data[m], dict_methods, 10) new_dictionary["list_size"] = get_int(method_name, "list_size", method_data, dict_methods, 10)
new_dictionary["list_buffer"] = get_int(method_name, "list_buffer", self.data[m], dict_methods, 20) new_dictionary["list_buffer"] = get_int(method_name, "list_buffer", method_data, dict_methods, 20)
self.methods.append((method_name, [new_dictionary])) self.methods.append((method_name, [new_dictionary]))
elif method_name == "mal_season": elif method_name == "mal_season":
new_dictionary = {"sort_by": "anime_num_list_users"} new_dictionary = {"sort_by": "anime_num_list_users"}
dict_methods = {dm.lower(): dm for dm in self.data[m]} dict_methods = {dm.lower(): dm for dm in method_data}
if "sort_by" not in dict_methods: if "sort_by" not in dict_methods:
logger.warning("Collection Warning: mal_season sort_by attribute not found using members as default") logger.warning("Collection Warning: mal_season sort_by attribute not found using members as default")
elif not self.data[m][dict_methods["sort_by"]]: elif not method_data[dict_methods["sort_by"]]:
logger.warning("Collection Warning: mal_season sort_by attribute is blank using members as default") logger.warning("Collection Warning: mal_season sort_by attribute is blank using members as default")
elif self.data[m][dict_methods["sort_by"]] not in util.mal_season_sort: elif method_data[dict_methods["sort_by"]] not in util.mal_season_sort:
logger.warning(f"Collection Warning: mal_season sort_by attribute {self.data[m][dict_methods['sort_by']]} invalid must be either 'members' or 'score' using members as default") logger.warning(f"Collection Warning: mal_season sort_by attribute {method_data[dict_methods['sort_by']]} invalid must be either 'members' or 'score' using members as default")
else: else:
new_dictionary["sort_by"] = util.mal_season_sort[self.data[m][dict_methods["sort_by"]]] new_dictionary["sort_by"] = util.mal_season_sort[method_data[dict_methods["sort_by"]]]
if current_time.month in [1, 2, 3]: new_dictionary["season"] = "winter" if current_time.month in [1, 2, 3]: new_dictionary["season"] = "winter"
elif current_time.month in [4, 5, 6]: new_dictionary["season"] = "spring" elif current_time.month in [4, 5, 6]: new_dictionary["season"] = "spring"
@ -551,49 +551,49 @@ class CollectionBuilder:
if "season" not in dict_methods: if "season" not in dict_methods:
logger.warning(f"Collection Warning: mal_season season attribute not found using the current season: {new_dictionary['season']} as default") logger.warning(f"Collection Warning: mal_season season attribute not found using the current season: {new_dictionary['season']} as default")
elif not self.data[m][dict_methods["season"]]: elif not method_data[dict_methods["season"]]:
logger.warning(f"Collection Warning: mal_season season attribute is blank using the current season: {new_dictionary['season']} as default") logger.warning(f"Collection Warning: mal_season season attribute is blank using the current season: {new_dictionary['season']} as default")
elif self.data[m][dict_methods["season"]] not in util.pretty_seasons: elif method_data[dict_methods["season"]] not in util.pretty_seasons:
logger.warning(f"Collection Warning: mal_season season attribute {self.data[m][dict_methods['season']]} invalid must be either 'winter', 'spring', 'summer' or 'fall' using the current season: {new_dictionary['season']} as default") logger.warning(f"Collection Warning: mal_season season attribute {method_data[dict_methods['season']]} invalid must be either 'winter', 'spring', 'summer' or 'fall' using the current season: {new_dictionary['season']} as default")
else: else:
new_dictionary["season"] = self.data[m][dict_methods["season"]] new_dictionary["season"] = method_data[dict_methods["season"]]
new_dictionary["year"] = get_int(method_name, "year", self.data[m], dict_methods, current_time.year, minimum=1917, maximum=current_time.year + 1) new_dictionary["year"] = get_int(method_name, "year", method_data, dict_methods, current_time.year, minimum=1917, maximum=current_time.year + 1)
new_dictionary["limit"] = get_int(method_name, "limit", self.data[m], dict_methods, 100, maximum=500) new_dictionary["limit"] = get_int(method_name, "limit", method_data, dict_methods, 100, maximum=500)
self.methods.append((method_name, [new_dictionary])) self.methods.append((method_name, [new_dictionary]))
elif method_name == "mal_userlist": elif method_name == "mal_userlist":
new_dictionary = {"status": "all", "sort_by": "list_score"} new_dictionary = {"status": "all", "sort_by": "list_score"}
dict_methods = {dm.lower(): dm for dm in self.data[m]} dict_methods = {dm.lower(): dm for dm in method_data}
if "username" not in dict_methods: if "username" not in dict_methods:
raise Failed("Collection Error: mal_userlist username attribute is required") raise Failed("Collection Error: mal_userlist username attribute is required")
elif not self.data[m][dict_methods["username"]]: elif not method_data[dict_methods["username"]]:
raise Failed("Collection Error: mal_userlist username attribute is blank") raise Failed("Collection Error: mal_userlist username attribute is blank")
else: else:
new_dictionary["username"] = self.data[m][dict_methods["username"]] new_dictionary["username"] = method_data[dict_methods["username"]]
if "status" not in dict_methods: if "status" not in dict_methods:
logger.warning("Collection Warning: mal_season status attribute not found using all as default") logger.warning("Collection Warning: mal_season status attribute not found using all as default")
elif not self.data[m][dict_methods["status"]]: elif not method_data[dict_methods["status"]]:
logger.warning("Collection Warning: mal_season status attribute is blank using all as default") logger.warning("Collection Warning: mal_season status attribute is blank using all as default")
elif self.data[m][dict_methods["status"]] not in util.mal_userlist_status: elif method_data[dict_methods["status"]] not in util.mal_userlist_status:
logger.warning(f"Collection Warning: mal_season status attribute {self.data[m][dict_methods['status']]} invalid must be either 'all', 'watching', 'completed', 'on_hold', 'dropped' or 'plan_to_watch' using all as default") logger.warning(f"Collection Warning: mal_season status attribute {method_data[dict_methods['status']]} invalid must be either 'all', 'watching', 'completed', 'on_hold', 'dropped' or 'plan_to_watch' using all as default")
else: else:
new_dictionary["status"] = util.mal_userlist_status[self.data[m][dict_methods["status"]]] new_dictionary["status"] = util.mal_userlist_status[method_data[dict_methods["status"]]]
if "sort_by" not in dict_methods: if "sort_by" not in dict_methods:
logger.warning("Collection Warning: mal_season sort_by attribute not found using score as default") logger.warning("Collection Warning: mal_season sort_by attribute not found using score as default")
elif not self.data[m][dict_methods["sort_by"]]: elif not method_data[dict_methods["sort_by"]]:
logger.warning("Collection Warning: mal_season sort_by attribute is blank using score as default") logger.warning("Collection Warning: mal_season sort_by attribute is blank using score as default")
elif self.data[m][dict_methods["sort_by"]] not in util.mal_userlist_sort: elif method_data[dict_methods["sort_by"]] not in util.mal_userlist_sort:
logger.warning(f"Collection Warning: mal_season sort_by attribute {self.data[m][dict_methods['sort_by']]} invalid must be either 'score', 'last_updated', 'title' or 'start_date' using score as default") logger.warning(f"Collection Warning: mal_season sort_by attribute {method_data[dict_methods['sort_by']]} invalid must be either 'score', 'last_updated', 'title' or 'start_date' using score as default")
else: else:
new_dictionary["sort_by"] = util.mal_userlist_sort[self.data[m][dict_methods["sort_by"]]] new_dictionary["sort_by"] = util.mal_userlist_sort[method_data[dict_methods["sort_by"]]]
new_dictionary["limit"] = get_int(method_name, "limit", self.data[m], dict_methods, 100, maximum=1000) new_dictionary["limit"] = get_int(method_name, "limit", method_data, dict_methods, 100, maximum=1000)
self.methods.append((method_name, [new_dictionary])) self.methods.append((method_name, [new_dictionary]))
elif "anilist" in method_name: elif "anilist" in method_name:
new_dictionary = {"sort_by": "score"} new_dictionary = {"sort_by": "score"}
dict_methods = {dm.lower(): dm for dm in self.data[m]} dict_methods = {dm.lower(): dm for dm in method_data}
if method_name == "anilist_season": if method_name == "anilist_season":
if current_time.month in [12, 1, 2]: new_dictionary["season"] = "winter" if current_time.month in [12, 1, 2]: new_dictionary["season"] = "winter"
elif current_time.month in [3, 4, 5]: new_dictionary["season"] = "spring" elif current_time.month in [3, 4, 5]: new_dictionary["season"] = "spring"
@ -602,51 +602,51 @@ class CollectionBuilder:
if "season" not in dict_methods: if "season" not in dict_methods:
logger.warning(f"Collection Warning: anilist_season season attribute not found using the current season: {new_dictionary['season']} as default") logger.warning(f"Collection Warning: anilist_season season attribute not found using the current season: {new_dictionary['season']} as default")
elif not self.data[m][dict_methods["season"]]: elif not method_data[dict_methods["season"]]:
logger.warning(f"Collection Warning: anilist_season season attribute is blank using the current season: {new_dictionary['season']} as default") logger.warning(f"Collection Warning: anilist_season season attribute is blank using the current season: {new_dictionary['season']} as default")
elif self.data[m][dict_methods["season"]] not in util.pretty_seasons: elif method_data[dict_methods["season"]] not in util.pretty_seasons:
logger.warning(f"Collection Warning: anilist_season season attribute {self.data[m][dict_methods['season']]} invalid must be either 'winter', 'spring', 'summer' or 'fall' using the current season: {new_dictionary['season']} as default") logger.warning(f"Collection Warning: anilist_season season attribute {method_data[dict_methods['season']]} invalid must be either 'winter', 'spring', 'summer' or 'fall' using the current season: {new_dictionary['season']} as default")
else: else:
new_dictionary["season"] = self.data[m][dict_methods["season"]] new_dictionary["season"] = method_data[dict_methods["season"]]
new_dictionary["year"] = get_int(method_name, "year", self.data[m], dict_methods, current_time.year, minimum=1917, maximum=current_time.year + 1) new_dictionary["year"] = get_int(method_name, "year", method_data, dict_methods, current_time.year, minimum=1917, maximum=current_time.year + 1)
elif method_name == "anilist_genre": elif method_name == "anilist_genre":
if "genre" not in dict_methods: if "genre" not in dict_methods:
raise Failed(f"Collection Warning: anilist_genre genre attribute not found") raise Failed(f"Collection Warning: anilist_genre genre attribute not found")
elif not self.data[m][dict_methods["genre"]]: elif not method_data[dict_methods["genre"]]:
raise Failed(f"Collection Warning: anilist_genre genre attribute is blank") raise Failed(f"Collection Warning: anilist_genre genre attribute is blank")
else: else:
new_dictionary["genre"] = self.config.AniList.validate_genre(self.data[m][dict_methods["genre"]]) new_dictionary["genre"] = self.config.AniList.validate_genre(method_data[dict_methods["genre"]])
elif method_name == "anilist_tag": elif method_name == "anilist_tag":
if "tag" not in dict_methods: if "tag" not in dict_methods:
raise Failed(f"Collection Warning: anilist_tag tag attribute not found") raise Failed(f"Collection Warning: anilist_tag tag attribute not found")
elif not self.data[m][dict_methods["tag"]]: elif not method_data[dict_methods["tag"]]:
raise Failed(f"Collection Warning: anilist_tag tag attribute is blank") raise Failed(f"Collection Warning: anilist_tag tag attribute is blank")
else: else:
new_dictionary["tag"] = self.config.AniList.validate_tag(self.data[m][dict_methods["tag"]]) new_dictionary["tag"] = self.config.AniList.validate_tag(method_data[dict_methods["tag"]])
if "sort_by" not in dict_methods: if "sort_by" not in dict_methods:
logger.warning(f"Collection Warning: {method_name} sort_by attribute not found using score as default") logger.warning(f"Collection Warning: {method_name} sort_by attribute not found using score as default")
elif not self.data[m][dict_methods["sort_by"]]: elif not method_data[dict_methods["sort_by"]]:
logger.warning(f"Collection Warning: {method_name} sort_by attribute is blank using score as default") logger.warning(f"Collection Warning: {method_name} sort_by attribute is blank using score as default")
elif str(self.data[m][dict_methods["sort_by"]]).lower() not in ["score", "popular"]: elif str(method_data[dict_methods["sort_by"]]).lower() not in ["score", "popular"]:
logger.warning(f"Collection Warning: {method_name} sort_by attribute {self.data[m][dict_methods['sort_by']]} invalid must be either 'score' or 'popular' using score as default") logger.warning(f"Collection Warning: {method_name} sort_by attribute {method_data[dict_methods['sort_by']]} invalid must be either 'score' or 'popular' using score as default")
else: else:
new_dictionary["sort_by"] = self.data[m][dict_methods["sort_by"]] new_dictionary["sort_by"] = method_data[dict_methods["sort_by"]]
new_dictionary["limit"] = get_int(method_name, "limit", self.data[m], dict_methods, 0, maximum=500) new_dictionary["limit"] = get_int(method_name, "limit", method_data, dict_methods, 0, maximum=500)
self.methods.append((method_name, [new_dictionary])) self.methods.append((method_name, [new_dictionary]))
else: else:
raise Failed(f"Collection Error: {m} attribute is not a dictionary: {self.data[m]}") raise Failed(f"Collection Error: {method_name} attribute is not a dictionary: {method_data}")
elif method_name in util.count_lists: elif method_name in util.count_lists:
list_count = util.regex_first_int(self.data[m], "List Size", default=10) list_count = util.regex_first_int(method_data, "List Size", default=10)
if list_count < 1: if list_count < 1:
logger.warning(f"Collection Warning: {method_name} must be an integer greater then 0 defaulting to 10") logger.warning(f"Collection Warning: {method_name} must be an integer greater then 0 defaulting to 10")
list_count = 10 list_count = 10
self.methods.append((method_name, [list_count])) self.methods.append((method_name, [list_count]))
elif "tvdb" in method_name: elif "tvdb" in method_name:
values = util.get_list(self.data[m]) values = util.get_list(method_data)
if method_name[-8:] == "_details": if method_name[-8:] == "_details":
if method_name == "tvdb_movie_details": if method_name == "tvdb_movie_details":
item = config.TVDb.get_movie(self.library.Plex.language, values[0]) item = config.TVDb.get_movie(self.library.Plex.language, values[0])
@ -670,7 +670,7 @@ class CollectionBuilder:
else: else:
self.methods.append((method_name, values)) self.methods.append((method_name, values))
elif method_name in util.tmdb_lists: elif method_name in util.tmdb_lists:
values = config.TMDb.validate_tmdb_list(util.get_int_list(self.data[m], f"TMDb {util.tmdb_type[method_name]} ID"), util.tmdb_type[method_name]) values = config.TMDb.validate_tmdb_list(util.get_int_list(method_data, f"TMDb {util.tmdb_type[method_name]} ID"), util.tmdb_type[method_name])
if method_name[-8:] == "_details": if method_name[-8:] == "_details":
if method_name in ["tmdb_collection_details", "tmdb_movie_details", "tmdb_show_details"]: if method_name in ["tmdb_collection_details", "tmdb_movie_details", "tmdb_show_details"]:
item = config.TMDb.get_movie_show_or_collection(values[0], self.library.is_movie) item = config.TMDb.get_movie_show_or_collection(values[0], self.library.is_movie)
@ -694,13 +694,13 @@ class CollectionBuilder:
else: else:
self.methods.append((method_name, values)) self.methods.append((method_name, values))
elif method_name in util.all_lists: elif method_name in util.all_lists:
self.methods.append((method_name, util.get_list(self.data[m]))) self.methods.append((method_name, util.get_list(method_data)))
elif method_name not in util.other_attributes: elif method_name not in util.other_attributes:
raise Failed(f"Collection Error: {method_name} attribute not supported") raise Failed(f"Collection Error: {method_name} attribute not supported")
elif m in util.all_lists or m in util.method_alias or m in util.plex_searches: elif method_name in util.all_lists or method_name in util.method_alias or method_name in util.plex_searches:
raise Failed(f"Collection Error: {m} attribute is blank") raise Failed(f"Collection Error: {method_name} attribute is blank")
else: else:
logger.warning(f"Collection Warning: {m} attribute is blank") logger.warning(f"Collection Warning: {method_name} 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:

@ -267,47 +267,47 @@ class Config:
self.libraries = [] self.libraries = []
try: libs = check_for_attribute(self.data, "libraries", throw=True) try: libs = check_for_attribute(self.data, "libraries", throw=True)
except Failed as e: raise Failed(e) except Failed as e: raise Failed(e)
for lib in libs: for library_name, lib in libs.items():
util.separator() util.separator()
params = {} params = {}
if "library_name" in libs[lib] and libs[lib]["library_name"]: if "library_name" in lib and lib["library_name"]:
params["name"] = str(libs[lib]["library_name"]) params["name"] = str(lib["library_name"])
logger.info(f"Connecting to {params['name']} ({lib}) Library...") logger.info(f"Connecting to {params['name']} ({library_name}) Library...")
else: else:
params["name"] = str(lib) params["name"] = str(library_name)
logger.info(f"Connecting to {params['name']} Library...") logger.info(f"Connecting to {params['name']} Library...")
params["asset_directory"] = check_for_attribute(libs[lib], "asset_directory", parent="settings", var_type="list_path", default=self.general["asset_directory"], default_is_none=True, save=False) params["asset_directory"] = check_for_attribute(lib, "asset_directory", parent="settings", var_type="list_path", default=self.general["asset_directory"], default_is_none=True, save=False)
if params["asset_directory"] is None: if params["asset_directory"] is None:
logger.warning("Config Warning: Assets will not be used asset_directory attribute must be set under config or under this specific Library") logger.warning("Config Warning: Assets will not be used asset_directory attribute must be set under config or under this specific Library")
if "settings" in libs[lib] and libs[lib]["settings"] and "sync_mode" in libs[lib]["settings"]: if "settings" in lib and lib["settings"] and "sync_mode" in lib["settings"]:
params["sync_mode"] = check_for_attribute(libs[lib], "sync_mode", parent="settings", test_list=["append", "sync"], options=" append (Only Add Items to the Collection)\n sync (Add & Remove Items from the Collection)", default=self.general["sync_mode"], do_print=False, save=False) params["sync_mode"] = check_for_attribute(lib, "sync_mode", parent="settings", test_list=["append", "sync"], options=" append (Only Add Items to the Collection)\n sync (Add & Remove Items from the Collection)", default=self.general["sync_mode"], do_print=False, save=False)
else: else:
params["sync_mode"] = check_for_attribute(libs[lib], "sync_mode", test_list=["append", "sync"], options=" append (Only Add Items to the Collection)\n sync (Add & Remove Items from the Collection)", default=self.general["sync_mode"], do_print=False, save=False) params["sync_mode"] = check_for_attribute(lib, "sync_mode", test_list=["append", "sync"], options=" append (Only Add Items to the Collection)\n sync (Add & Remove Items from the Collection)", default=self.general["sync_mode"], do_print=False, save=False)
if "settings" in libs[lib] and libs[lib]["settings"] and "show_unmanaged" in libs[lib]["settings"]: if "settings" in lib and lib["settings"] and "show_unmanaged" in lib["settings"]:
params["show_unmanaged"] = check_for_attribute(libs[lib], "show_unmanaged", parent="settings", var_type="bool", default=self.general["show_unmanaged"], do_print=False, save=False) params["show_unmanaged"] = check_for_attribute(lib, "show_unmanaged", parent="settings", var_type="bool", default=self.general["show_unmanaged"], do_print=False, save=False)
else: else:
params["show_unmanaged"] = check_for_attribute(libs[lib], "show_unmanaged", var_type="bool", default=self.general["show_unmanaged"], do_print=False, save=False) params["show_unmanaged"] = check_for_attribute(lib, "show_unmanaged", var_type="bool", default=self.general["show_unmanaged"], do_print=False, save=False)
if "settings" in libs[lib] and libs[lib]["settings"] and "show_filtered" in libs[lib]["settings"]: if "settings" in lib and lib["settings"] and "show_filtered" in lib["settings"]:
params["show_filtered"] = check_for_attribute(libs[lib], "show_filtered", parent="settings", var_type="bool", default=self.general["show_filtered"], do_print=False, save=False) params["show_filtered"] = check_for_attribute(lib, "show_filtered", parent="settings", var_type="bool", default=self.general["show_filtered"], do_print=False, save=False)
else: else:
params["show_filtered"] = check_for_attribute(libs[lib], "show_filtered", var_type="bool", default=self.general["show_filtered"], do_print=False, save=False) params["show_filtered"] = check_for_attribute(lib, "show_filtered", var_type="bool", default=self.general["show_filtered"], do_print=False, save=False)
if "settings" in libs[lib] and libs[lib]["settings"] and "show_missing" in libs[lib]["settings"]: if "settings" in lib and lib["settings"] and "show_missing" in lib["settings"]:
params["show_missing"] = check_for_attribute(libs[lib], "show_missing", parent="settings", var_type="bool", default=self.general["show_missing"], do_print=False, save=False) params["show_missing"] = check_for_attribute(lib, "show_missing", parent="settings", var_type="bool", default=self.general["show_missing"], do_print=False, save=False)
else: else:
params["show_missing"] = check_for_attribute(libs[lib], "show_missing", var_type="bool", default=self.general["show_missing"], do_print=False, save=False) params["show_missing"] = check_for_attribute(lib, "show_missing", var_type="bool", default=self.general["show_missing"], do_print=False, save=False)
if "settings" in libs[lib] and libs[lib]["settings"] and "save_missing" in libs[lib]["settings"]: if "settings" in lib and lib["settings"] and "save_missing" in lib["settings"]:
params["save_missing"] = check_for_attribute(libs[lib], "save_missing", parent="settings", var_type="bool", default=self.general["save_missing"], do_print=False, save=False) params["save_missing"] = check_for_attribute(lib, "save_missing", parent="settings", var_type="bool", default=self.general["save_missing"], do_print=False, save=False)
else: else:
params["save_missing"] = check_for_attribute(libs[lib], "save_missing", var_type="bool", default=self.general["save_missing"], do_print=False, save=False) params["save_missing"] = check_for_attribute(lib, "save_missing", var_type="bool", default=self.general["save_missing"], do_print=False, save=False)
if "mass_genre_update" in libs[lib] and libs[lib]["mass_genre_update"]: if "mass_genre_update" in lib and lib["mass_genre_update"]:
params["mass_genre_update"] = check_for_attribute(libs[lib], "mass_genre_update", test_list=["tmdb", "omdb"], options=" tmdb (Use TMDb Metadata)\n omdb (Use IMDb Metadata through OMDb)", default_is_none=True, save=False) params["mass_genre_update"] = check_for_attribute(lib, "mass_genre_update", test_list=["tmdb", "omdb"], options=" tmdb (Use TMDb Metadata)\n omdb (Use IMDb Metadata through OMDb)", default_is_none=True, save=False)
else: else:
params["mass_genre_update"] = None params["mass_genre_update"] = None
@ -316,12 +316,12 @@ class Config:
logger.error("Config Error: mass_genre_update cannot be omdb without a successful OMDb Connection") logger.error("Config Error: mass_genre_update cannot be omdb without a successful OMDb Connection")
try: try:
params["metadata_path"] = check_for_attribute(libs[lib], "metadata_path", var_type="path", default=os.path.join(default_dir, f"{lib}.yml"), throw=True) params["metadata_path"] = check_for_attribute(lib, "metadata_path", var_type="path", default=os.path.join(default_dir, f"{library_name}.yml"), throw=True)
params["library_type"] = check_for_attribute(libs[lib], "library_type", test_list=["movie", "show"], options=" movie (For Movie Libraries)\n show (For Show Libraries)", throw=True) params["library_type"] = check_for_attribute(lib, "library_type", test_list=["movie", "show"], options=" movie (For Movie Libraries)\n show (For Show Libraries)", throw=True)
params["plex"] = {} params["plex"] = {}
params["plex"]["url"] = check_for_attribute(libs[lib], "url", parent="plex", default=self.general["plex"]["url"], req_default=True, save=False) params["plex"]["url"] = check_for_attribute(lib, "url", parent="plex", default=self.general["plex"]["url"], req_default=True, save=False)
params["plex"]["token"] = check_for_attribute(libs[lib], "token", parent="plex", default=self.general["plex"]["token"], req_default=True, save=False) params["plex"]["token"] = check_for_attribute(lib, "token", parent="plex", default=self.general["plex"]["token"], req_default=True, save=False)
params["plex"]["timeout"] = check_for_attribute(libs[lib], "timeout", parent="plex", var_type="int", default=self.general["plex"]["timeout"], save=False) params["plex"]["timeout"] = check_for_attribute(lib, "timeout", parent="plex", var_type="int", default=self.general["plex"]["timeout"], save=False)
library = PlexAPI(params, self.TMDb, self.TVDb) library = PlexAPI(params, self.TMDb, self.TVDb)
logger.info(f"{params['name']} Library Connection Successful") logger.info(f"{params['name']} Library Connection Successful")
except Failed as e: except Failed as e:
@ -329,47 +329,47 @@ class Config:
logger.info(f"{params['name']} Library Connection Failed") logger.info(f"{params['name']} Library Connection Failed")
continue continue
if self.general["radarr"]["url"] or "radarr" in libs[lib]: if self.general["radarr"]["url"] or "radarr" in lib:
logger.info(f"Connecting to {params['name']} library's Radarr...") logger.info(f"Connecting to {params['name']} library's Radarr...")
radarr_params = {} radarr_params = {}
try: try:
radarr_params["url"] = check_for_attribute(libs[lib], "url", parent="radarr", default=self.general["radarr"]["url"], req_default=True, save=False) radarr_params["url"] = check_for_attribute(lib, "url", parent="radarr", default=self.general["radarr"]["url"], req_default=True, save=False)
radarr_params["token"] = check_for_attribute(libs[lib], "token", parent="radarr", default=self.general["radarr"]["token"], req_default=True, save=False) radarr_params["token"] = check_for_attribute(lib, "token", parent="radarr", default=self.general["radarr"]["token"], req_default=True, save=False)
radarr_params["version"] = check_for_attribute(libs[lib], "version", parent="radarr", test_list=["v2", "v3"], options=" v2 (For Radarr 0.2)\n v3 (For Radarr 3.0)", default=self.general["radarr"]["version"], save=False) radarr_params["version"] = check_for_attribute(lib, "version", parent="radarr", test_list=["v2", "v3"], options=" v2 (For Radarr 0.2)\n v3 (For Radarr 3.0)", default=self.general["radarr"]["version"], save=False)
radarr_params["quality_profile"] = check_for_attribute(libs[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["root_folder_path"] = check_for_attribute(libs[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["add"] = check_for_attribute(libs[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["search"] = check_for_attribute(libs[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)
radarr_params["tag"] = check_for_attribute(libs[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)
library.Radarr = RadarrAPI(self.TMDb, radarr_params) library.Radarr = RadarrAPI(self.TMDb, radarr_params)
except Failed as e: except Failed as e:
util.print_multiline(e) util.print_multiline(e)
logger.info(f"{params['name']} library's Radarr Connection {'Failed' if library.Radarr is None else 'Successful'}") logger.info(f"{params['name']} library's Radarr Connection {'Failed' if library.Radarr is None else 'Successful'}")
if self.general["sonarr"]["url"] or "sonarr" in libs[lib]: if self.general["sonarr"]["url"] or "sonarr" in lib:
logger.info(f"Connecting to {params['name']} library's Sonarr...") logger.info(f"Connecting to {params['name']} library's Sonarr...")
sonarr_params = {} sonarr_params = {}
try: try:
sonarr_params["url"] = check_for_attribute(libs[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(libs[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(libs[lib], "version", parent="sonarr", test_list=["v2", "v3"], options=" v2 (For Sonarr 0.2)\n v3 (For Sonarr 3.0)", default=self.general["sonarr"]["version"], save=False) sonarr_params["version"] = check_for_attribute(lib, "version", parent="sonarr", test_list=["v2", "v3"], options=" v2 (For Sonarr 0.2)\n v3 (For Sonarr 3.0)", default=self.general["sonarr"]["version"], save=False)
sonarr_params["quality_profile"] = check_for_attribute(libs[lib], "quality_profile", parent="sonarr", default=self.general["sonarr"]["quality_profile"], req_default=True, 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["root_folder_path"] = check_for_attribute(libs[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["add"] = check_for_attribute(libs[lib], "add", parent="sonarr", var_type="bool", default=self.general["sonarr"]["add"], save=False) sonarr_params["add"] = check_for_attribute(lib, "add", parent="sonarr", var_type="bool", default=self.general["sonarr"]["add"], save=False)
sonarr_params["search"] = check_for_attribute(libs[lib], "search", parent="sonarr", var_type="bool", default=self.general["sonarr"]["search"], 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(libs[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(libs[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)
library.Sonarr = SonarrAPI(self.TVDb, sonarr_params, library.Plex.language) library.Sonarr = SonarrAPI(self.TVDb, sonarr_params, library.Plex.language)
except Failed as e: except Failed as e:
util.print_multiline(e) util.print_multiline(e)
logger.info(f"{params['name']} library's Sonarr Connection {'Failed' if library.Sonarr is None else 'Successful'}") logger.info(f"{params['name']} library's Sonarr Connection {'Failed' if library.Sonarr is None else 'Successful'}")
if self.general["tautulli"]["url"] or "tautulli" in libs[lib]: if self.general["tautulli"]["url"] or "tautulli" in lib:
logger.info(f"Connecting to {params['name']} library's Tautulli...") logger.info(f"Connecting to {params['name']} library's Tautulli...")
tautulli_params = {} tautulli_params = {}
try: try:
tautulli_params["url"] = check_for_attribute(libs[lib], "url", parent="tautulli", default=self.general["tautulli"]["url"], req_default=True, save=False) tautulli_params["url"] = check_for_attribute(lib, "url", parent="tautulli", default=self.general["tautulli"]["url"], req_default=True, save=False)
tautulli_params["apikey"] = check_for_attribute(libs[lib], "apikey", parent="tautulli", default=self.general["tautulli"]["apikey"], req_default=True, save=False) tautulli_params["apikey"] = check_for_attribute(lib, "apikey", parent="tautulli", default=self.general["tautulli"]["apikey"], req_default=True, save=False)
library.Tautulli = TautulliAPI(tautulli_params) library.Tautulli = TautulliAPI(tautulli_params)
except Failed as e: except Failed as e:
util.print_multiline(e) util.print_multiline(e)
@ -404,11 +404,11 @@ class Config:
util.separator(f"{library.name} Library {'Test ' if test else ''}Collections") util.separator(f"{library.name} Library {'Test ' if test else ''}Collections")
collections = {c: library.collections[c] for c in util.get_list(requested_collections) if c in library.collections} if requested_collections else library.collections collections = {c: library.collections[c] for c in util.get_list(requested_collections) if c in library.collections} if requested_collections else library.collections
if collections: if collections:
for c in collections: for mapping_name, collection_attrs in collections.items():
if test and ("test" not in collections[c] or collections[c]["test"] is not True): if test and ("test" not in collection_attrs or collection_attrs["test"] is not True):
no_template_test = True no_template_test = True
if "template" in collections[c] and collections[c]["template"]: if "template" in collection_attrs and collection_attrs["template"]:
for data_template in util.get_list(collections[c]["template"], split=False): for data_template in util.get_list(collection_attrs["template"], split=False):
if "name" in data_template \ if "name" in data_template \
and data_template["name"] \ and data_template["name"] \
and library.templates \ and library.templates \
@ -421,13 +421,14 @@ class Config:
continue continue
try: try:
logger.info("") logger.info("")
util.separator(f"{c} Collection") util.separator(f"{mapping_name} Collection")
logger.info("") logger.info("")
rating_key_map = {} rating_key_map = {}
try: try:
builder = CollectionBuilder(self, library, c, collections[c]) builder = CollectionBuilder(self, library, mapping_name, collection_attrs)
except Failed as ef: except Failed as ef:
util.print_stacktrace()
util.print_multiline(ef, error=True) util.print_multiline(ef, error=True)
continue continue
except Exception as ee: except Exception as ee:
@ -436,11 +437,11 @@ class Config:
continue continue
try: try:
collection_obj = library.get_collection(c) collection_obj = library.get_collection(mapping_name)
collection_name = collection_obj.title collection_name = collection_obj.title
except Failed: except Failed:
collection_obj = None collection_obj = None
collection_name = c collection_name = mapping_name
if len(builder.schedule) > 0: if len(builder.schedule) > 0:
util.print_multiline(builder.schedule, info=True) util.print_multiline(builder.schedule, info=True)

@ -230,21 +230,21 @@ class PlexAPI:
logger.info("") logger.info("")
if not self.metadata: if not self.metadata:
raise Failed("No metadata to edit") raise Failed("No metadata to edit")
for m in self.metadata: for mapping_name, meta in self.metadata.items():
methods = {mm.lower(): mm for mm in self.metadata[m]} methods = {mm.lower(): mm for mm in meta}
if test and ("test" not in methods or self.metadata[m][methods["test"]] is not True): if test and ("test" not in methods or meta[methods["test"]] is not True):
continue continue
logger.info("") logger.info("")
util.separator() util.separator()
logger.info("") logger.info("")
year = None year = None
if "year" in methods: if "year" in methods:
year = util.check_number(self.metadata[m][methods["year"]], "year", minimum=1800, maximum=datetime.now().year + 1) year = util.check_number(meta[methods["year"]], "year", minimum=1800, maximum=datetime.now().year + 1)
title = m title = mapping_name
if "title" in methods: if "title" in methods:
if self.metadata[m][methods["title"]] is None: logger.error("Metadata Error: title attribute is blank") if meta[methods["title"]] is None: logger.error("Metadata Error: title attribute is blank")
else: title = self.metadata[m][methods["title"]] else: title = meta[methods["title"]]
item = self.search_item(title, year=year) item = self.search_item(title, year=year)
@ -252,15 +252,15 @@ class PlexAPI:
item = self.search_item(f"{title} (SUB)", year=year) item = self.search_item(f"{title} (SUB)", year=year)
if item is None and "alt_title" in methods: if item is None and "alt_title" in methods:
if self.metadata[m][methods["alt_title"]] is None: if meta[methods["alt_title"]] is None:
logger.error("Metadata Error: alt_title attribute is blank") logger.error("Metadata Error: alt_title attribute is blank")
else: else:
alt_title = self.metadata[m]["alt_title"] alt_title = meta["alt_title"]
item = self.search_item(alt_title, year=year) item = self.search_item(alt_title, year=year)
if item is None: if item is None:
logger.error(f"Plex Error: Item {m} not found") logger.error(f"Plex Error: Item {mapping_name} not found")
logger.error(f"Skipping {m}") logger.error(f"Skipping {mapping_name}")
continue continue
item_type = "Movie" if self.is_movie else "Show" item_type = "Movie" if self.is_movie else "Show"
@ -269,9 +269,9 @@ class PlexAPI:
tmdb_item = None tmdb_item = None
try: try:
if "tmdb_id" in methods: if "tmdb_id" in methods:
if self.metadata[m][methods["tmdb_id"]] is None: logger.error("Metadata Error: tmdb_id attribute is blank") if meta[methods["tmdb_id"]] is None: logger.error("Metadata Error: tmdb_id attribute is blank")
elif self.is_show: logger.error("Metadata Error: tmdb_id attribute only works with movie libraries") elif self.is_show: logger.error("Metadata Error: tmdb_id attribute only works with movie libraries")
else: tmdb_item = TMDb.get_show(util.regex_first_int(self.metadata[m][methods["tmdb_id"]], "Show")) else: tmdb_item = TMDb.get_show(util.regex_first_int(meta[methods["tmdb_id"]], "Show"))
except Failed as e: except Failed as e:
logger.error(e) logger.error(e)
@ -294,33 +294,33 @@ class PlexAPI:
logger.info(f"Detail: {name} updated to {value}") logger.info(f"Detail: {name} updated to {value}")
else: else:
logger.error(f"Metadata Error: {name} attribute is blank") logger.error(f"Metadata Error: {name} attribute is blank")
add_edit("title", item.title, self.metadata[m], methods, value=title) add_edit("title", item.title, meta, methods, value=title)
add_edit("sort_title", item.titleSort, self.metadata[m], methods, key="titleSort") add_edit("sort_title", item.titleSort, meta, methods, key="titleSort")
add_edit("originally_available", str(item.originallyAvailableAt)[:-9], self.metadata[m], methods, key="originallyAvailableAt", value=originally_available) add_edit("originally_available", str(item.originallyAvailableAt)[:-9], meta, methods, key="originallyAvailableAt", value=originally_available)
add_edit("rating", item.rating, self.metadata[m], methods, value=rating) add_edit("rating", item.rating, meta, methods, value=rating)
add_edit("content_rating", item.contentRating, self.metadata[m], methods, key="contentRating") add_edit("content_rating", item.contentRating, meta, methods, key="contentRating")
add_edit("original_title", item.originalTitle, self.metadata[m], methods, key="originalTitle", value=original_title) add_edit("original_title", item.originalTitle, meta, methods, key="originalTitle", value=original_title)
add_edit("studio", item.studio, self.metadata[m], methods, value=studio) add_edit("studio", item.studio, meta, methods, value=studio)
add_edit("tagline", item.tagline, self.metadata[m], methods, value=tagline) add_edit("tagline", item.tagline, meta, methods, value=tagline)
add_edit("summary", item.summary, self.metadata[m], methods, value=summary) add_edit("summary", item.summary, meta, methods, value=summary)
if len(edits) > 0: if len(edits) > 0:
logger.debug(f"Details Update: {edits}") logger.debug(f"Details Update: {edits}")
try: try:
item.edit(**edits) item.edit(**edits)
item.reload() item.reload()
logger.info(f"{item_type}: {m} Details Update Successful") logger.info(f"{item_type}: {mapping_name} Details Update Successful")
except BadRequest: except BadRequest:
util.print_stacktrace() util.print_stacktrace()
logger.error(f"{item_type}: {m} Details Update Failed") logger.error(f"{item_type}: {mapping_name} Details Update Failed")
else: else:
logger.info(f"{item_type}: {m} Details Update Not Needed") logger.info(f"{item_type}: {mapping_name} Details Update Not Needed")
advance_edits = {} advance_edits = {}
if self.is_show: if self.is_show:
if "episode_sorting" in methods: if "episode_sorting" in methods:
if self.metadata[m][methods["episode_sorting"]]: if meta[methods["episode_sorting"]]:
method_data = str(self.metadata[m][methods["episode_sorting"]]).lower() method_data = str(meta[methods["episode_sorting"]]).lower()
if method_data in ["default", "oldest", "newest"]: if method_data in ["default", "oldest", "newest"]:
if method_data == "default" and item.episodeSort != "-1": if method_data == "default" and item.episodeSort != "-1":
advance_edits["episodeSort"] = "-1" advance_edits["episodeSort"] = "-1"
@ -331,13 +331,13 @@ class PlexAPI:
if "episodeSort" in advance_edits: if "episodeSort" in advance_edits:
logger.info(f"Detail: episode_sorting updated to {method_data}") logger.info(f"Detail: episode_sorting updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['episode_sorting']]} episode_sorting attribute invalid") logger.error(f"Metadata Error: {meta[methods['episode_sorting']]} episode_sorting attribute invalid")
else: else:
logger.error(f"Metadata Error: episode_sorting attribute is blank") logger.error(f"Metadata Error: episode_sorting attribute is blank")
if "keep_episodes" in methods: if "keep_episodes" in methods:
if self.metadata[m][methods["keep_episodes"]]: if meta[methods["keep_episodes"]]:
method_data = str(self.metadata[m][methods["keep_episodes"]]).lower() method_data = str(meta[methods["keep_episodes"]]).lower()
if method_data in ["all", "5_latest", "3_latest", "latest", "past_3", "past_7", "past_30"]: if method_data in ["all", "5_latest", "3_latest", "latest", "past_3", "past_7", "past_30"]:
if method_data == "all" and item.autoDeletionItemPolicyUnwatchedLibrary != 0: if method_data == "all" and item.autoDeletionItemPolicyUnwatchedLibrary != 0:
advance_edits["autoDeletionItemPolicyUnwatchedLibrary"] = 0 advance_edits["autoDeletionItemPolicyUnwatchedLibrary"] = 0
@ -356,13 +356,13 @@ class PlexAPI:
if "autoDeletionItemPolicyUnwatchedLibrary" in advance_edits: if "autoDeletionItemPolicyUnwatchedLibrary" in advance_edits:
logger.info(f"Detail: keep_episodes updated to {method_data}") logger.info(f"Detail: keep_episodes updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['keep_episodes']]} keep_episodes attribute invalid") logger.error(f"Metadata Error: {meta[methods['keep_episodes']]} keep_episodes attribute invalid")
else: else:
logger.error(f"Metadata Error: keep_episodes attribute is blank") logger.error(f"Metadata Error: keep_episodes attribute is blank")
if "delete_episodes" in methods: if "delete_episodes" in methods:
if self.metadata[m][methods["delete_episodes"]]: if meta[methods["delete_episodes"]]:
method_data = str(self.metadata[m][methods["delete_episodes"]]).lower() method_data = str(meta[methods["delete_episodes"]]).lower()
if method_data in ["never", "day", "week", "refresh"]: if method_data in ["never", "day", "week", "refresh"]:
if method_data == "never" and item.autoDeletionItemPolicyWatchedLibrary != 0: if method_data == "never" and item.autoDeletionItemPolicyWatchedLibrary != 0:
advance_edits["autoDeletionItemPolicyWatchedLibrary"] = 0 advance_edits["autoDeletionItemPolicyWatchedLibrary"] = 0
@ -375,13 +375,13 @@ class PlexAPI:
if "autoDeletionItemPolicyWatchedLibrary" in advance_edits: if "autoDeletionItemPolicyWatchedLibrary" in advance_edits:
logger.info(f"Detail: delete_episodes updated to {method_data}") logger.info(f"Detail: delete_episodes updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['delete_episodes']]} delete_episodes attribute invalid") logger.error(f"Metadata Error: {meta[methods['delete_episodes']]} delete_episodes attribute invalid")
else: else:
logger.error(f"Metadata Error: delete_episodes attribute is blank") logger.error(f"Metadata Error: delete_episodes attribute is blank")
if "season_display" in methods: if "season_display" in methods:
if self.metadata[m][methods["season_display"]]: if meta[methods["season_display"]]:
method_data = str(self.metadata[m][methods["season_display"]]).lower() method_data = str(meta[methods["season_display"]]).lower()
if method_data in ["default", "hide", "show"]: if method_data in ["default", "hide", "show"]:
if method_data == "default" and item.flattenSeasons != -1: if method_data == "default" and item.flattenSeasons != -1:
advance_edits["flattenSeasons"] = -1 advance_edits["flattenSeasons"] = -1
@ -392,13 +392,13 @@ class PlexAPI:
if "flattenSeasons" in advance_edits: if "flattenSeasons" in advance_edits:
logger.info(f"Detail: season_display updated to {method_data}") logger.info(f"Detail: season_display updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['season_display']]} season_display attribute invalid") logger.error(f"Metadata Error: {meta[methods['season_display']]} season_display attribute invalid")
else: else:
logger.error(f"Metadata Error: season_display attribute is blank") logger.error(f"Metadata Error: season_display attribute is blank")
if "episode_ordering" in methods: if "episode_ordering" in methods:
if self.metadata[m][methods["episode_ordering"]]: if meta[methods["episode_ordering"]]:
method_data = str(self.metadata[m][methods["episode_ordering"]]).lower() method_data = str(meta[methods["episode_ordering"]]).lower()
if method_data in ["default", "tmdb_aired", "tvdb_aired", "tvdb_dvd", "tvdb_absolute"]: if method_data in ["default", "tmdb_aired", "tvdb_aired", "tvdb_dvd", "tvdb_absolute"]:
if method_data == "default" and item.showOrdering is not None: if method_data == "default" and item.showOrdering is not None:
advance_edits["showOrdering"] = None advance_edits["showOrdering"] = None
@ -413,13 +413,13 @@ class PlexAPI:
if "showOrdering" in advance_edits: if "showOrdering" in advance_edits:
logger.info(f"Detail: episode_ordering updated to {method_data}") logger.info(f"Detail: episode_ordering updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['episode_ordering']]} episode_ordering attribute invalid") logger.error(f"Metadata Error: {meta[methods['episode_ordering']]} episode_ordering attribute invalid")
else: else:
logger.error(f"Metadata Error: episode_ordering attribute is blank") logger.error(f"Metadata Error: episode_ordering attribute is blank")
if "metadata_language" in methods: if "metadata_language" in methods:
if self.metadata[m][methods["metadata_language"]]: if meta[methods["metadata_language"]]:
method_data = str(self.metadata[m][methods["metadata_language"]]).lower() method_data = str(meta[methods["metadata_language"]]).lower()
lower_languages = {la.lower(): la for la in util.plex_languages} lower_languages = {la.lower(): la for la in util.plex_languages}
if method_data in lower_languages: if method_data in lower_languages:
if method_data == "default" and item.languageOverride is None: if method_data == "default" and item.languageOverride is None:
@ -429,13 +429,13 @@ class PlexAPI:
if "languageOverride" in advance_edits: if "languageOverride" in advance_edits:
logger.info(f"Detail: metadata_language updated to {method_data}") logger.info(f"Detail: metadata_language updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['metadata_language']]} metadata_language attribute invalid") logger.error(f"Metadata Error: {meta[methods['metadata_language']]} metadata_language attribute invalid")
else: else:
logger.error(f"Metadata Error: metadata_language attribute is blank") logger.error(f"Metadata Error: metadata_language attribute is blank")
if "use_original_title" in methods: if "use_original_title" in methods:
if self.metadata[m][methods["use_original_title"]]: if meta[methods["use_original_title"]]:
method_data = str(self.metadata[m][methods["use_original_title"]]).lower() method_data = str(meta[methods["use_original_title"]]).lower()
if method_data in ["default", "no", "yes"]: if method_data in ["default", "no", "yes"]:
if method_data == "default" and item.useOriginalTitle != -1: if method_data == "default" and item.useOriginalTitle != -1:
advance_edits["useOriginalTitle"] = -1 advance_edits["useOriginalTitle"] = -1
@ -446,7 +446,7 @@ class PlexAPI:
if "useOriginalTitle" in advance_edits: if "useOriginalTitle" in advance_edits:
logger.info(f"Detail: use_original_title updated to {method_data}") logger.info(f"Detail: use_original_title updated to {method_data}")
else: else:
logger.error(f"Metadata Error: {self.metadata[m][methods['use_original_title']]} use_original_title attribute invalid") logger.error(f"Metadata Error: {meta[methods['use_original_title']]} use_original_title attribute invalid")
else: else:
logger.error(f"Metadata Error: use_original_title attribute is blank") logger.error(f"Metadata Error: use_original_title attribute is blank")
@ -457,29 +457,29 @@ class PlexAPI:
logger.info(check_dict) logger.info(check_dict)
item.editAdvanced(**advance_edits) item.editAdvanced(**advance_edits)
item.reload() item.reload()
logger.info(f"{item_type}: {m} Advanced Details Update Successful") logger.info(f"{item_type}: {mapping_name} Advanced Details Update Successful")
except BadRequest: except BadRequest:
util.print_stacktrace() util.print_stacktrace()
logger.error(f"{item_type}: {m} Details Update Failed") logger.error(f"{item_type}: {mapping_name} Details Update Failed")
else: else:
logger.info(f"{item_type}: {m} Details Update Not Needed") logger.info(f"{item_type}: {mapping_name} Details Update Not Needed")
genres = [] genres = []
if tmdb_item: if tmdb_item:
genres.extend([genre.name for genre in tmdb_item.genres]) genres.extend([genre.name for genre in tmdb_item.genres])
if "genre" in methods: if "genre" in methods:
if self.metadata[m][methods["genre"]]: if meta[methods["genre"]]:
genres.extend(util.get_list(self.metadata[m][methods["genre"]])) genres.extend(util.get_list(meta[methods["genre"]]))
else: else:
logger.error("Metadata Error: genre attribute is blank") logger.error("Metadata Error: genre attribute is blank")
if len(genres) > 0: if len(genres) > 0:
item_genres = [genre.tag for genre in item.genres] item_genres = [genre.tag for genre in item.genres]
if "genre_sync_mode" in methods: if "genre_sync_mode" in methods:
if self.metadata[m][methods["genre_sync_mode"]] is None: if meta[methods["genre_sync_mode"]] is None:
logger.error("Metadata Error: genre_sync_mode attribute is blank defaulting to append") logger.error("Metadata Error: genre_sync_mode attribute is blank defaulting to append")
elif str(self.metadata[m][methods["genre_sync_mode"]]).lower() not in ["append", "sync"]: elif str(meta[methods["genre_sync_mode"]]).lower() not in ["append", "sync"]:
logger.error("Metadata Error: genre_sync_mode attribute must be either 'append' or 'sync' defaulting to append") logger.error("Metadata Error: genre_sync_mode attribute must be either 'append' or 'sync' defaulting to append")
elif str(self.metadata[m]["genre_sync_mode"]).lower() == "sync": elif str(meta["genre_sync_mode"]).lower() == "sync":
for genre in (g for g in item_genres if g not in genres): for genre in (g for g in item_genres if g not in genres):
item.removeGenre(genre) item.removeGenre(genre)
logger.info(f"Detail: Genre {genre} removed") logger.info(f"Detail: Genre {genre} removed")
@ -488,15 +488,15 @@ class PlexAPI:
logger.info(f"Detail: Genre {genre} added") logger.info(f"Detail: Genre {genre} added")
if "label" in methods: if "label" in methods:
if self.metadata[m][methods["label"]]: if meta[methods["label"]]:
item_labels = [label.tag for label in item.labels] item_labels = [label.tag for label in item.labels]
labels = util.get_list(self.metadata[m][methods["label"]]) labels = util.get_list(meta[methods["label"]])
if "label_sync_mode" in methods: if "label_sync_mode" in methods:
if self.metadata[m][methods["label_sync_mode"]] is None: if meta[methods["label_sync_mode"]] is None:
logger.error("Metadata Error: label_sync_mode attribute is blank defaulting to append") logger.error("Metadata Error: label_sync_mode attribute is blank defaulting to append")
elif str(self.metadata[m][methods["label_sync_mode"]]).lower() not in ["append", "sync"]: elif str(meta[methods["label_sync_mode"]]).lower() not in ["append", "sync"]:
logger.error("Metadata Error: label_sync_mode attribute must be either 'append' or 'sync' defaulting to append") logger.error("Metadata Error: label_sync_mode attribute must be either 'append' or 'sync' defaulting to append")
elif str(self.metadata[m][methods["label_sync_mode"]]).lower() == "sync": elif str(meta[methods["label_sync_mode"]]).lower() == "sync":
for label in (la for la in item_labels if la not in labels): for label in (la for la in item_labels if la not in labels):
item.removeLabel(label) item.removeLabel(label)
logger.info(f"Detail: Label {label} removed") logger.info(f"Detail: Label {label} removed")
@ -507,15 +507,15 @@ class PlexAPI:
logger.error("Metadata Error: label attribute is blank") logger.error("Metadata Error: label attribute is blank")
if "seasons" in methods and self.is_show: if "seasons" in methods and self.is_show:
if self.metadata[m][methods["seasons"]]: if meta[methods["seasons"]]:
for season_id in self.metadata[m][methods["seasons"]]: for season_id in meta[methods["seasons"]]:
logger.info("") logger.info("")
logger.info(f"Updating season {season_id} of {m}...") logger.info(f"Updating season {season_id} of {mapping_name}...")
if isinstance(season_id, int): if isinstance(season_id, int):
try: season = item.season(season_id) try: season = item.season(season_id)
except NotFound: logger.error(f"Metadata Error: Season: {season_id} not found") except NotFound: logger.error(f"Metadata Error: Season: {season_id} not found")
else: else:
season_dict = self.metadata[m][methods["seasons"]][season_id] season_dict = meta[methods["seasons"]][season_id]
season_methods = {sm.lower(): sm for sm in season_dict} season_methods = {sm.lower(): sm for sm in season_dict}
if "title" in season_methods and season_dict[season_methods["title"]]: if "title" in season_methods and season_dict[season_methods["title"]]:
@ -552,19 +552,19 @@ class PlexAPI:
logger.error("Metadata Error: seasons attribute is blank") logger.error("Metadata Error: seasons attribute is blank")
if "episodes" in methods and self.is_show: if "episodes" in methods and self.is_show:
if self.metadata[m][methods["episodes"]]: if meta[methods["episodes"]]:
for episode_str in self.metadata[m][methods["episodes"]]: for episode_str in meta[methods["episodes"]]:
logger.info("") logger.info("")
match = re.search("[Ss]\\d+[Ee]\\d+", episode_str) match = re.search("[Ss]\\d+[Ee]\\d+", episode_str)
if match: if match:
output = match.group(0)[1:].split("E" if "E" in match.group(0) else "e") output = match.group(0)[1:].split("E" if "E" in match.group(0) else "e")
episode_id = int(output[0]) episode_id = int(output[0])
season_id = int(output[1]) season_id = int(output[1])
logger.info(f"Updating episode S{episode_id}E{season_id} of {m}...") logger.info(f"Updating episode S{episode_id}E{season_id} of {mapping_name}...")
try: episode = item.episode(season=season_id, episode=episode_id) try: episode = item.episode(season=season_id, episode=episode_id)
except NotFound: logger.error(f"Metadata Error: episode {episode_id} of season {season_id} not found") except NotFound: logger.error(f"Metadata Error: episode {episode_id} of season {season_id} not found")
else: else:
episode_dict = self.metadata[m][methods["episodes"]][episode_str] episode_dict = meta[methods["episodes"]][episode_str]
episode_methods = {em.lower(): em for em in episode_dict} episode_methods = {em.lower(): em for em in episode_dict}
if "title" in episode_methods and episode_dict[episode_methods["title"]]: if "title" in episode_methods and episode_dict[episode_methods["title"]]:

Loading…
Cancel
Save