From 1e2fc349110535763df9515397d0a590ab01a2af Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Mon, 16 Aug 2021 01:41:04 -0400 Subject: [PATCH] final cleanup for v1.12.0 --- config/config.yml.template | 4 +- modules/anilist.py | 14 ++- modules/builder.py | 205 ++++++++++++++++++------------------- modules/config.py | 8 +- modules/convert.py | 2 +- modules/mal.py | 28 +++-- modules/plex.py | 2 +- modules/radarr.py | 1 + modules/sonarr.py | 1 + plex_meta_manager.py | 10 +- requirements.txt | 3 +- 11 files changed, 146 insertions(+), 132 deletions(-) diff --git a/config/config.yml.template b/config/config.yml.template index 9a2bb7d6..d6b0d925 100644 --- a/config/config.yml.template +++ b/config/config.yml.template @@ -89,6 +89,6 @@ mal: token_type: expires_in: refresh_token: -anidb: - username: ###### - optional +anidb: # Optional + username: ###### password: ###### \ No newline at end of file diff --git a/modules/anilist.py b/modules/anilist.py index d73ecc76..6e82d86c 100644 --- a/modules/anilist.py +++ b/modules/anilist.py @@ -4,10 +4,7 @@ from modules.util import Failed logger = logging.getLogger("Plex Meta Manager") -builders = [ - "anilist_genre", "anilist_id", "anilist_popular", "anilist_relations", - "anilist_season", "anilist_studio", "anilist_tag", "anilist_top_rated", "anilist_search" -] +builders = ["anilist_id", "anilist_popular", "anilist_relations", "anilist_studio", "anilist_top_rated", "anilist_search"] pretty_names = {"score": "Average Score", "popular": "Popularity"} attr_translation = {"year": "seasonYear", "adult": "isAdult", "start": "startDate", "end": "endDate", "tag_category": "tagCategory", "score": "averageScore", "min_tag_percent": "minimumTagRank"} mod_translation = {"": "in", "not": "not_in", "before": "greater", "after": "lesser", "gt": "greater", "gte": "greater", "lt": "lesser", "lte": "lesser"} @@ -17,12 +14,13 @@ mod_searches = [ "episodes.gt", "episodes.gte", "episodes.lt", "episodes.lte", "duration.gt", "duration.gte", "duration.lt", "duration.lte", "score.gt", "score.gte", "score.lt", "score.lte", "popularity.gt", "popularity.gte", "popularity.lt", "popularity.lte" ] -no_mod_searches = ["season", "year", "adult", "min_tag_percent"] +no_mod_searches = ["search", "season", "year", "adult", "min_tag_percent"] searches = mod_searches + no_mod_searches search_types = { - "season": "MediaSeason", "seasonYear": "Int", "isAdult": "Boolean", "startDate": "FuzzyDateInt", "endDate": "FuzzyDateInt", - "format": "[MediaFormat]", "status": "[MediaStatus]", "genre": "[String]", "tag": "[String]", "tagCategory": "[String]", - "episodes": "Int", "duration": "Int", "averageScore": "Int", "popularity": "Int", "minimumTagRank": "Int" + "search": "String", "season": "MediaSeason", "seasonYear": "Int", "isAdult": "Boolean", "minimumTagRank": "Int", + "startDate": "FuzzyDateInt", "endDate": "FuzzyDateInt", "format": "[MediaFormat]", "status": "[MediaStatus]", + "genre": "[String]", "tag": "[String]", "tagCategory": "[String]", + "episodes": "Int", "duration": "Int", "averageScore": "Int", "popularity": "Int" } media_season = {"winter": "WINTER", "spring": "SPRING", "summer": "SUMMER", "fall": "FALL"} media_format = {"tv": "TV", "short": "TV_SHORT", "movie": "MOVIE", "special": "SPECIAL", "ova": "OVA", "ona": "ONA", "music": "MUSIC"} diff --git a/modules/builder.py b/modules/builder.py index 950650c9..235cce03 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -39,7 +39,8 @@ method_alias = { "years": "year", "show_year": "year", "show_years": "year", "show_title": "title", "seasonyear": "year", "isadult": "adult", "startdate": "start", "enddate": "end", "averagescore": "score", - "minimum_tag_percentage": "min_tag_percent", "minimumtagrank": "min_tag_percent", "minimum_tag_rank": "min_tag_percent" + "minimum_tag_percentage": "min_tag_percent", "minimumtagrank": "min_tag_percent", "minimum_tag_rank": "min_tag_percent", + "anilist_tag": "anilist_search", "anilist_genre": "anilist_search", "anilist_season": "anilist_search" } filter_translation = { "actor": "actors", @@ -74,15 +75,15 @@ summary_details = [ ] poster_details = ["url_poster", "tmdb_poster", "tmdb_profile", "tvdb_poster", "file_poster"] background_details = ["url_background", "tmdb_background", "tvdb_background", "file_background"] -boolean_details = ["visible_library", "visible_home", "visible_shared", "show_filtered", "show_missing", "save_missing", "item_assets", "create_asset_folders", "released_missing_only"] +boolean_details = ["visible_library", "visible_home", "visible_shared", "show_filtered", "show_missing", "save_missing", "item_assets", "missing_only_released"] string_details = ["sort_title", "content_rating", "name_mapping"] ignored_details = ["smart_filter", "smart_label", "smart_url", "run_again", "schedule", "sync_mode", "template", "test", "tmdb_person", "build_collection", "collection_order", "validate_builders"] details = ["collection_mode", "collection_order", "label"] + boolean_details + string_details collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \ poster_details + background_details + summary_details + string_details item_details = ["item_label", "item_radarr_tag", "item_sonarr_tag", "item_overlay"] + list(plex.item_advance_keys.keys()) -radarr_details = ["radarr_add", "radarr_folder", "radarr_monitor", "radarr_search", "radarr_availability", "radarr_quality", "radarr_tag"] -sonarr_details = ["sonarr_add", "sonarr_folder", "sonarr_monitor", "sonarr_language", "sonarr_series", "sonarr_quality", "sonarr_season", "sonarr_search", "sonarr_cutoff_search", "sonarr_tag"] +radarr_details = ["radarr_add", "radarr_add_existing", "radarr_folder", "radarr_monitor", "radarr_search", "radarr_availability", "radarr_quality", "radarr_tag"] +sonarr_details = ["sonarr_add", "sonarr_add_existing", "sonarr_folder", "sonarr_monitor", "sonarr_language", "sonarr_series", "sonarr_quality", "sonarr_season", "sonarr_search", "sonarr_cutoff_search", "sonarr_tag"] all_filters = [ "actor", "actor.not", "audio_language", "audio_language.not", @@ -133,35 +134,34 @@ smart_url_invalid = ["filters", "run_again", "sync_mode", "show_filtered", "show custom_sort_builders = [ "tmdb_list", "tmdb_popular", "tmdb_now_playing", "tmdb_top_rated", "tmdb_trending_daily", "tmdb_trending_weekly", "tmdb_discover", - "tvdb_list", - "imdb_list", + "tvdb_list", "imdb_list", "stevenlu_popular", "anidb_popular", "trakt_list", "trakt_trending", "trakt_popular", "trakt_recommended", "trakt_watched", "trakt_collected", "tautulli_popular", "tautulli_watched", "letterboxd_list", "icheckmovies_list", - "anidb_popular", - "anilist_top_rated", "anilist_popular", "anilist_season", "anilist_studio", "anilist_genre", "anilist_tag", + "anilist_top_rated", "anilist_popular", "anilist_season", "anilist_studio", "anilist_genre", "anilist_tag", "anilist_search", "mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_movie", "mal_ova", "mal_special", "mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_producer" ] class CollectionBuilder: - def __init__(self, config, library, metadata, name, data): + def __init__(self, config, library, metadata, name, no_missing, data): self.config = config self.library = library self.metadata = metadata self.name = name + self.no_missing = no_missing self.data = data self.language = self.library.Plex.language self.details = { "show_filtered": self.library.show_filtered, "show_missing": self.library.show_missing, "save_missing": self.library.save_missing, - "released_missing_only": self.library.released_missing_only, + "missing_only_released": self.library.missing_only_released, "create_asset_folders": self.library.create_asset_folders, "item_assets": False } self.item_details = {} - self.radarr_options = {} - self.sonarr_options = {} + self.radarr_details = {} + self.sonarr_details = {} self.missing_movies = [] self.missing_shows = [] self.builders = [] @@ -175,8 +175,6 @@ class CollectionBuilder: self.backgrounds = {} self.summaries = {} self.schedule = "" - self.add_to_radarr = None - self.add_to_sonarr = None self.current_time = datetime.now() self.current_year = self.current_time.year @@ -538,21 +536,30 @@ class CollectionBuilder: if self.custom_sort and self.builders[0][0] not in custom_sort_builders: raise Failed(f"Collection Error: collection_order: custom cannot be used with {self.builders[0][0]}") - if self.add_to_radarr is None: - self.add_to_radarr = self.library.Radarr.add if self.library.Radarr else False - if self.add_to_sonarr is None: - self.add_to_sonarr = self.library.Sonarr.add if self.library.Sonarr else False + if "add" not in self.radarr_details: + self.radarr_details["add"] = self.library.Radarr.add if self.library.Radarr else False + if "add_existing" not in self.radarr_details: + self.radarr_details["add_existing"] = self.library.Radarr.add_existing if self.library.Radarr else False + + if "add" not in self.sonarr_details: + self.sonarr_details["add"] = self.library.Sonarr.add if self.library.Sonarr else False + if "add_existing" not in self.sonarr_details: + self.sonarr_details["add_existing"] = self.library.Sonarr.add_existing if self.library.Sonarr else False - if self.smart_url: - self.add_to_radarr = False - self.add_to_sonarr = False + if self.smart_url or self.collectionless: + self.radarr_details["add"] = False + self.radarr_details["add_existing"] = False + self.sonarr_details["add"] = False + self.sonarr_details["add_existing"] = False if self.collectionless: - self.add_to_radarr = False - self.add_to_sonarr = False self.details["collection_mode"] = "hide" self.sync = True + self.do_missing = not self.no_missing and (self.details["show_missing"] or self.details["save_missing"] + or (self.library.Radarr and self.radarr_details["add"]) + or (self.library.Sonarr and self.sonarr_details["add"])) + if self.build_collection: try: self.obj = self.library.get_collection(self.name) @@ -684,48 +691,44 @@ class CollectionBuilder: self.item_details[method_name] = str(method_data).lower() def _radarr(self, method_name, method_data): - if method_name == "radarr_add": - self.add_to_radarr = util.parse(method_name, method_data, datatype="bool") + if method_name in ["radarr_add", "radarr_add_existing", "radarr_monitor", "radarr_search"]: + self.radarr_details[method_name[7:]] = util.parse(method_name, method_data, datatype="bool") elif method_name == "radarr_folder": - self.radarr_options["folder"] = method_data - elif method_name in ["radarr_monitor", "radarr_search"]: - self.radarr_options[method_name[7:]] = util.parse(method_name, method_data, datatype="bool") + self.radarr_details["folder"] = method_data elif method_name == "radarr_availability": if str(method_data).lower() in radarr.availability_translation: - self.radarr_options["availability"] = str(method_data).lower() + self.radarr_details["availability"] = str(method_data).lower() else: raise Failed(f"Collection Error: {method_name} attribute must be either announced, cinemas, released or db") elif method_name == "radarr_quality": self.library.Radarr.get_profile_id(method_data) - self.radarr_options["quality"] = method_data + self.radarr_details["quality"] = method_data elif method_name == "radarr_tag": - self.radarr_options["tag"] = util.get_list(method_data) + self.radarr_details["tag"] = util.get_list(method_data) def _sonarr(self, method_name, method_data): - if method_name == "sonarr_add": - self.add_to_sonarr = util.parse(method_name, method_data, datatype="bool") + if method_name in ["sonarr_add", "sonarr_add_existing", "sonarr_season", "sonarr_search", "sonarr_cutoff_search"]: + self.sonarr_details[method_name[7:]] = util.parse(method_name, method_data, datatype="bool") elif method_name == "sonarr_folder": - self.sonarr_options["folder"] = method_data + self.sonarr_details["folder"] = method_data elif method_name == "sonarr_monitor": if str(method_data).lower() in sonarr.monitor_translation: - self.sonarr_options["monitor"] = str(method_data).lower() + self.sonarr_details["monitor"] = str(method_data).lower() else: raise Failed(f"Collection Error: {method_name} attribute must be either all, future, missing, existing, pilot, first, latest or none") elif method_name == "sonarr_quality": self.library.Sonarr.get_profile_id(method_data, "quality_profile") - self.sonarr_options["quality"] = method_data + self.sonarr_details["quality"] = method_data elif method_name == "sonarr_language": self.library.Sonarr.get_profile_id(method_data, "language_profile") - self.sonarr_options["language"] = method_data + self.sonarr_details["language"] = method_data elif method_name == "sonarr_series": if str(method_data).lower() in sonarr.series_type: - self.sonarr_options["series"] = str(method_data).lower() + self.sonarr_details["series"] = str(method_data).lower() else: raise Failed(f"Collection Error: {method_name} attribute must be either standard, daily, or anime") - elif method_name in ["sonarr_season", "sonarr_search", "sonarr_cutoff_search"]: - self.sonarr_options[method_name[7:]] = util.parse(method_name, method_data, datatype="bool") elif method_name == "sonarr_tag": - self.sonarr_options["tag"] = util.get_list(method_data) + self.sonarr_details["tag"] = util.get_list(method_data) def _anidb(self, method_name, method_data): if method_name == "anidb_popular": @@ -751,55 +754,47 @@ class CollectionBuilder: self.builders.append((method_name, anilist_id)) elif method_name in ["anilist_popular", "anilist_top_rated"]: self.builders.append((method_name, util.parse(method_name, method_data, datatype="int", default=10))) - elif method_name in ["anilist_season", "anilist_genre", "anilist_tag"]: + elif method_name == "anilist_search": + if self.current_time.month in [12, 1, 2]: current_season = "winter" + elif self.current_time.month in [3, 4, 5]: current_season = "spring" + elif self.current_time.month in [6, 7, 8]: current_season = "summer" + else: current_season = "fall" for dict_data, dict_methods in util.parse(method_name, method_data, datatype="dictlist"): new_dictionary = {} - if method_name == "anilist_season": - if self.current_time.month in [12, 1, 2]: new_dictionary["season"] = "winter" - elif self.current_time.month in [3, 4, 5]: new_dictionary["season"] = "spring" - elif self.current_time.month in [6, 7, 8]: new_dictionary["season"] = "summer" - elif self.current_time.month in [9, 10, 11]: new_dictionary["season"] = "fall" - new_dictionary["season"] = util.parse("season", dict_data, methods=dict_methods, parent=method_name, default=new_dictionary["season"], options=util.seasons) - new_dictionary["year"] = util.parse("year", dict_data, datatype="int", methods=dict_methods, default=self.current_year, parent=method_name, minimum=1917, maximum=self.current_year + 1) - elif method_name == "anilist_genre": - new_dictionary["genre"] = self.config.AniList.validate("Genre", util.parse("genre", dict_data, methods=dict_methods, parent=method_name)) - elif method_name == "anilist_tag": - new_dictionary["tag"] = self.config.AniList.validate("Tag", util.parse("tag", dict_data, methods=dict_methods, parent=method_name)) - elif method_name == "anilist_search": - for search_method, search_data in dict_data.items(): - search_attr, modifier, search_final = self._split(search_method) - if search_data is None: - raise Failed(f"Collection Error: {method_name} {search_final} attribute is blank") - elif search_final not in anilist.searches: - raise Failed(f"Collection Error: {method_name} {search_final} attribute not supported") - elif search_attr == "season": - if self.current_time.month in [12, 1, 2]: new_dictionary["season"] = "winter" - elif self.current_time.month in [3, 4, 5]: new_dictionary["season"] = "spring" - elif self.current_time.month in [6, 7, 8]: new_dictionary["season"] = "summer" - elif self.current_time.month in [9, 10, 11]: new_dictionary["season"] = "fall" - new_dictionary["season"] = util.parse("season", dict_data, parent=method_name, default=new_dictionary["season"], options=util.seasons) - if "year" not in dict_methods: - logger.warning(f"Collection Warning: {method_name} {search_final} attribute must be used with the year attribute using this year by default") - elif search_attr == "year": - if "season" not in dict_methods: - raise Failed(f"Collection Error: {method_name} {search_final} attribute must be used with the season attribute") - new_dictionary[search_attr] = util.parse(search_attr, search_data, datatype="int", parent=method_name, default=self.current_year, minimum=1917, maximum=self.current_year + 1) - elif search_attr == "adult": - new_dictionary[search_attr] = util.parse(search_attr, search_data, datatype="bool", parent=method_name) - elif search_attr in ["episodes", "duration", "score", "popularity"]: - new_dictionary[search_final] = util.parse(search_final, search_data, datatype="int", parent=method_name) - elif search_attr in ["format", "status", "genre", "tag", "tag_category"]: - new_dictionary[search_final] = self.config.AniList.validate(search_attr.replace("_", " ").title(), util.parse(search_final, search_data)) - elif search_attr in ["start", "end"]: - new_dictionary[search_final] = util.validate_date(search_data, f"{method_name} {search_final} attribute", return_as="%m/%d/%Y") - elif search_attr == "min_tag_percent": - new_dictionary[search_attr] = util.parse(search_attr, search_data, datatype="int", parent=method_name, minimum=0, maximum=100) - elif search_final not in ["sort_by", "limit"]: - raise Failed(f"Collection Error: {method_name} {search_final} attribute not supported") - if len(new_dictionary) > 0: - raise Failed(f"Collection Error: {method_name} must have at least one valid search option") + for search_method, search_data in dict_data.items(): + search_attr, modifier, search_final = self._split(search_method) + if search_data is None: + raise Failed(f"Collection Error: {method_name} {search_final} attribute is blank") + elif search_final not in anilist.searches: + raise Failed(f"Collection Error: {method_name} {search_final} attribute not supported") + elif search_attr == "season": + new_dictionary[search_attr] = util.parse(search_attr, search_data, parent=method_name, default=current_season, options=util.seasons) + if "year" not in dict_methods: + logger.warning(f"Collection Warning: {method_name} year attribute not found using this year: {self.current_year} by default") + new_dictionary["year"] = self.current_year + elif search_attr == "year": + new_dictionary[search_attr] = util.parse(search_attr, search_data, datatype="int", parent=method_name, default=self.current_year, minimum=1917, maximum=self.current_year + 1) + if "season" not in dict_methods: + logger.warning(f"Collection Warning: {method_name} season attribute not found using this season: {current_season} by default") + new_dictionary["season"] = current_season + elif search_attr == "adult": + new_dictionary[search_attr] = util.parse(search_attr, search_data, datatype="bool", parent=method_name) + elif search_attr in ["episodes", "duration", "score", "popularity"]: + new_dictionary[search_final] = util.parse(search_final, search_data, datatype="int", parent=method_name) + elif search_attr in ["format", "status", "genre", "tag", "tag_category"]: + new_dictionary[search_final] = self.config.AniList.validate(search_attr.replace("_", " ").title(), util.parse(search_final, search_data)) + elif search_attr in ["start", "end"]: + new_dictionary[search_final] = util.validate_date(search_data, f"{method_name} {search_final} attribute", return_as="%m/%d/%Y") + elif search_attr == "min_tag_percent": + new_dictionary[search_attr] = util.parse(search_attr, search_data, datatype="int", parent=method_name, minimum=0, maximum=100) + elif search_attr == "search": + new_dictionary[search_attr] = str(search_data) + elif search_final not in ["sort_by", "limit"]: + raise Failed(f"Collection Error: {method_name} {search_final} attribute not supported") + if len(new_dictionary) > 0: + raise Failed(f"Collection Error: {method_name} must have at least one valid search option") new_dictionary["sort_by"] = util.parse("sort_by", dict_data, methods=dict_methods, parent=method_name, default="score", options=["score", "popular"]) - new_dictionary["limit"] = util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=0, parent=method_name, maximum=500) + new_dictionary["limit"] = util.parse("limit", dict_data, datatype="int", methods=dict_methods, default=0, parent=method_name) self.builders.append((method_name, new_dictionary)) def _icheckmovies(self, method_name, method_data): @@ -1029,7 +1024,7 @@ class CollectionBuilder: else: logger.error(message) - def find_rating_keys(self, no_missing): + def find_rating_keys(self): for method, value in self.builders: ids = [] rating_keys = [] @@ -1094,9 +1089,7 @@ class CollectionBuilder: if input_id in self.library.imdb_map: rating_keys.append(self.library.imdb_map[input_id][0]) else: - if (self.details["show_missing"] or self.details["save_missing"] - or (self.library.Radarr and self.add_to_radarr) - or (self.library.Sonarr and self.add_to_sonarr)) and not no_missing: + if self.do_missing: try: tmdb_id, tmdb_type = self.config.Convert.imdb_to_tmdb(input_id) if tmdb_type == "movie": @@ -1553,7 +1546,7 @@ class CollectionBuilder: logger.error(e) continue current_title = f"{movie.title} ({util.validate_date(movie.release_date, 'test').year})" if movie.release_date else movie.title - if self.check_tmdb_filter(missing_id, True, item=movie, check_released=self.details["released_missing_only"]): + if self.check_tmdb_filter(missing_id, True, item=movie, check_released=self.details["missing_only_released"]): missing_movies_with_names.append((current_title, missing_id)) if self.details["show_missing"] is True: logger.info(f"{self.name} Collection | ? | {current_title} (TMDb: {missing_id})") @@ -1565,12 +1558,12 @@ class CollectionBuilder: if len(missing_movies_with_names) > 0: if self.details["save_missing"] is True: self.library.add_missing(self.name, missing_movies_with_names, True) - if self.run_again or (self.library.Radarr and (self.add_to_radarr or "item_radarr_tag" in self.item_details)): + if self.run_again or (self.library.Radarr and (self.radarr_details["add"] or "item_radarr_tag" in self.item_details)): missing_tmdb_ids = [missing_id for title, missing_id in missing_movies_with_names] if self.library.Radarr: - if self.add_to_radarr: + if self.radarr_details["add"]: try: - self.library.Radarr.add_tmdb(missing_tmdb_ids, **self.radarr_options) + self.library.Radarr.add_tmdb(missing_tmdb_ids, **self.radarr_details) except Failed as e: logger.error(e) if "item_radarr_tag" in self.item_details: @@ -1589,7 +1582,7 @@ class CollectionBuilder: logger.error(e) continue current_title = str(show.title.encode("ascii", "replace").decode()) - if self.check_tmdb_filter(missing_id, False, check_released=self.details["released_missing_only"]): + if self.check_tmdb_filter(missing_id, False, check_released=self.details["missing_only_released"]): missing_shows_with_names.append((current_title, missing_id)) if self.details["show_missing"] is True: logger.info(f"{self.name} Collection | ? | {current_title} (TVDB: {missing_id})") @@ -1601,12 +1594,12 @@ class CollectionBuilder: if len(missing_shows_with_names) > 0: if self.details["save_missing"] is True: self.library.add_missing(self.name, missing_shows_with_names, False) - if self.run_again or (self.library.Sonarr and (self.add_to_sonarr or "item_sonarr_tag" in self.item_details)): + if self.run_again or (self.library.Sonarr and (self.sonarr_details["add"] or "item_sonarr_tag" in self.item_details)): missing_tvdb_ids = [missing_id for title, missing_id in missing_shows_with_names] if self.library.Sonarr: - if self.add_to_sonarr: + if self.sonarr_details["add"]: try: - self.library.Sonarr.add_tvdb(missing_tvdb_ids, **self.sonarr_options) + self.library.Sonarr.add_tvdb(missing_tvdb_ids, **self.sonarr_details) except Failed as e: logger.error(e) if "item_sonarr_tag" in self.item_details: @@ -1693,9 +1686,9 @@ class CollectionBuilder: except Failed as e: logger.error(e) self.library.edit_tags("label", item, add_tags=add_tags, remove_tags=remove_tags, sync_tags=sync_tags) - if "item_radarr_tag" in self.item_details and item.ratingKey in self.library.movie_rating_key_map: + if item.ratingKey in self.library.movie_rating_key_map: tmdb_ids.append(self.library.movie_rating_key_map[item.ratingKey]) - if "item_sonarr_tag" in self.item_details and item.ratingKey in self.library.show_rating_key_map: + if item.ratingKey in self.library.show_rating_key_map: tvdb_ids.append(self.library.show_rating_key_map[item.ratingKey]) advance_edits = {} for method_name, method_data in self.item_details.items(): @@ -1706,10 +1699,16 @@ class CollectionBuilder: self.library.edit_item(item, item.title, "Movie" if self.library.is_movie else "Show", advance_edits, advanced=True) if len(tmdb_ids) > 0: - self.library.Radarr.edit_tags(tmdb_ids, self.item_details["item_radarr_tag"], self.item_details["apply_tags"]) + if "item_radarr_tag" in self.item_details: + self.library.Radarr.edit_tags(tmdb_ids, self.item_details["item_radarr_tag"], self.item_details["apply_tags"]) + if self.radarr_details["add_existing"]: + self.library.Radarr.add_tmdb(tmdb_ids, **self.radarr_details) if len(tvdb_ids) > 0: - self.library.Sonarr.edit_tags(tvdb_ids, self.item_details["item_sonarr_tag"], self.item_details["apply_tags"]) + if "item_sonarr_tag" in self.item_details: + self.library.Sonarr.edit_tags(tvdb_ids, self.item_details["item_sonarr_tag"], self.item_details["apply_tags"]) + if self.sonarr_details["add_existing"]: + self.library.Sonarr.add_tvdb(tvdb_ids, **self.sonarr_details) for rating_key in rating_keys: try: diff --git a/modules/config.py b/modules/config.py index 4386d4be..efad2b29 100644 --- a/modules/config.py +++ b/modules/config.py @@ -183,7 +183,7 @@ class Config: "show_filtered": check_for_attribute(self.data, "show_filtered", parent="settings", var_type="bool", default=False), "show_missing": check_for_attribute(self.data, "show_missing", parent="settings", var_type="bool", default=True), "save_missing": check_for_attribute(self.data, "save_missing", parent="settings", var_type="bool", default=True), - "released_missing_only": check_for_attribute(self.data, "released_missing_only", parent="settings", var_type="bool", default=False), + "missing_only_released": check_for_attribute(self.data, "missing_only_released", parent="settings", var_type="bool", default=False), "create_asset_folders": check_for_attribute(self.data, "create_asset_folders", parent="settings", var_type="bool", default=False) } if self.general["cache"]: @@ -295,6 +295,7 @@ class Config: "url": check_for_attribute(self.data, "url", parent="radarr", var_type="url", default_is_none=True), "token": check_for_attribute(self.data, "token", parent="radarr", default_is_none=True), "add": check_for_attribute(self.data, "add", parent="radarr", var_type="bool", default=False), + "add_existing": check_for_attribute(self.data, "add_existing", parent="radarr", var_type="bool", default=False), "root_folder_path": check_for_attribute(self.data, "root_folder_path", parent="radarr", default_is_none=True), "monitor": check_for_attribute(self.data, "monitor", parent="radarr", var_type="bool", default=True), "availability": check_for_attribute(self.data, "availability", parent="radarr", test_list=radarr.availability_descriptions, default="announced"), @@ -306,6 +307,7 @@ class Config: "url": check_for_attribute(self.data, "url", parent="sonarr", var_type="url", default_is_none=True), "token": check_for_attribute(self.data, "token", parent="sonarr", default_is_none=True), "add": check_for_attribute(self.data, "add", parent="sonarr", var_type="bool", default=False), + "add_existing": check_for_attribute(self.data, "add_existing", parent="sonarr", var_type="bool", default=False), "root_folder_path": check_for_attribute(self.data, "root_folder_path", parent="sonarr", default_is_none=True), "monitor": check_for_attribute(self.data, "monitor", parent="sonarr", test_list=sonarr.monitor_descriptions, default="all"), "quality_profile": check_for_attribute(self.data, "quality_profile", parent="sonarr", default_is_none=True), @@ -349,7 +351,7 @@ class Config: params["show_filtered"] = check_for_attribute(lib, "show_filtered", parent="settings", var_type="bool", default=self.general["show_filtered"], 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) params["save_missing"] = check_for_attribute(lib, "save_missing", parent="settings", var_type="bool", default=self.general["save_missing"], do_print=False, save=False) - params["released_missing_only"] = check_for_attribute(lib, "released_missing_only", parent="settings", var_type="bool", default=self.general["released_missing_only"], do_print=False, save=False) + params["missing_only_released"] = check_for_attribute(lib, "missing_only_released", parent="settings", var_type="bool", default=self.general["missing_only_released"], do_print=False, save=False) params["create_asset_folders"] = check_for_attribute(lib, "create_asset_folders", parent="settings", var_type="bool", default=self.general["create_asset_folders"], do_print=False, save=False) params["mass_genre_update"] = check_for_attribute(lib, "mass_genre_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=lib and "mass_genre_update" in lib) @@ -427,6 +429,7 @@ class Config: "url": check_for_attribute(lib, "url", parent="radarr", var_type="url", default=self.general["radarr"]["url"], req_default=True, save=False), "token": check_for_attribute(lib, "token", parent="radarr", default=self.general["radarr"]["token"], req_default=True, save=False), "add": check_for_attribute(lib, "add", parent="radarr", var_type="bool", default=self.general["radarr"]["add"], save=False), + "add_existing": check_for_attribute(lib, "add_existing", parent="radarr", var_type="bool", default=self.general["radarr"]["add_existing"], save=False), "root_folder_path": check_for_attribute(lib, "root_folder_path", parent="radarr", default=self.general["radarr"]["root_folder_path"], req_default=True, save=False), "monitor": check_for_attribute(lib, "monitor", parent="radarr", var_type="bool", default=self.general["radarr"]["monitor"], save=False), "availability": check_for_attribute(lib, "availability", parent="radarr", test_list=radarr.availability_descriptions, default=self.general["radarr"]["availability"], save=False), @@ -451,6 +454,7 @@ class Config: "url": check_for_attribute(lib, "url", parent="sonarr", var_type="url", default=self.general["sonarr"]["url"], req_default=True, save=False), "token": check_for_attribute(lib, "token", parent="sonarr", default=self.general["sonarr"]["token"], req_default=True, save=False), "add": check_for_attribute(lib, "add", parent="sonarr", var_type="bool", default=self.general["sonarr"]["add"], save=False), + "add_existing": check_for_attribute(lib, "add_existing", parent="sonarr", var_type="bool", default=self.general["sonarr"]["add_existing"], save=False), "root_folder_path": check_for_attribute(lib, "root_folder_path", parent="sonarr", default=self.general["sonarr"]["root_folder_path"], req_default=True, save=False), "monitor": check_for_attribute(lib, "monitor", parent="sonarr", test_list=sonarr.monitor_descriptions, default=self.general["sonarr"]["monitor"], save=False), "quality_profile": check_for_attribute(lib, "quality_profile", parent="sonarr", default=self.general["sonarr"]["quality_profile"], req_default=True, save=False), diff --git a/modules/convert.py b/modules/convert.py index 015d0411..5391f50d 100644 --- a/modules/convert.py +++ b/modules/convert.py @@ -85,7 +85,7 @@ class Convert: if tvdb_id: ids.append((tvdb_id, "tvdb")) if tmdb_ids: - ids.extend((tmdb_ids, "tmdb")) + ids.extend([(t, "tmdb") for t in tmdb_ids]) except Failed as e: logger.error(e) return ids diff --git a/modules/mal.py b/modules/mal.py index 06c4ee9f..02416400 100644 --- a/modules/mal.py +++ b/modules/mal.py @@ -1,4 +1,4 @@ -import logging, re, secrets, time, webbrowser +import logging, math, re, secrets, time, webbrowser from modules import util from modules.util import Failed, TimeoutExpired from ruamel import yaml @@ -169,12 +169,26 @@ class MyAnimeList: if total_items < limit or limit <= 0: limit = total_items mal_ids = [] - for i in range(1, int(((total_items - 1) / 100) + 2)): - if i > 1: - data = self._jiken_request(f"/genre/anime/{genre_id}/{i}") - mal_ids.extend([anime["mal_id"] for anime in data["anime"]]) - if len(mal_ids) > limit: - return mal_ids[:limit] + num_of_pages = math.ceil(int(limit) / 100) + current_page = 1 + chances = 0 + while current_page <= num_of_pages: + if chances > 6: + logger.debug(data) + raise Failed("AniList Error: Connection Failed") + start_num = (current_page - 1) * 100 + 1 + util.print_return(f"Parsing Page {current_page}/{num_of_pages} {start_num}-{limit if current_page == num_of_pages else current_page * 100}") + if current_page > 1: + data = self._jiken_request(f"/genre/anime/{genre_id}/{current_page}") + if "anime" in data: + chances = 0 + mal_ids.extend([anime["mal_id"] for anime in data["anime"]]) + if len(mal_ids) > limit: + return mal_ids[:limit] + current_page += 1 + else: + chances += 1 + util.print_end() return mal_ids def _producer(self, producer_id, limit): diff --git a/modules/plex.py b/modules/plex.py index ba502322..e7e9f113 100644 --- a/modules/plex.py +++ b/modules/plex.py @@ -288,7 +288,7 @@ class Plex: self.show_filtered = params["show_filtered"] self.show_missing = params["show_missing"] self.save_missing = params["save_missing"] - self.released_missing_only = params["released_missing_only"] + self.missing_only_released = params["missing_only_released"] self.create_asset_folders = params["create_asset_folders"] self.mass_genre_update = params["mass_genre_update"] self.mass_audience_rating_update = params["mass_audience_rating_update"] diff --git a/modules/radarr.py b/modules/radarr.py index 8bb0909a..5d37bc1a 100644 --- a/modules/radarr.py +++ b/modules/radarr.py @@ -20,6 +20,7 @@ class Radarr: except ArrException as e: raise Failed(e) self.add = params["add"] + self.add_existing = params["add_existing"] self.root_folder_path = params["root_folder_path"] self.monitor = params["monitor"] self.availability = params["availability"] diff --git a/modules/sonarr.py b/modules/sonarr.py index bba35783..7c428c29 100644 --- a/modules/sonarr.py +++ b/modules/sonarr.py @@ -38,6 +38,7 @@ class Sonarr: except ArrException as e: raise Failed(e) self.add = params["add"] + self.add_existing = params["add_existing"] self.root_folder_path = params["root_folder_path"] self.monitor = params["monitor"] self.quality_profile = params["quality_profile"] diff --git a/plex_meta_manager.py b/plex_meta_manager.py index 19292c21..92ca3858 100644 --- a/plex_meta_manager.py +++ b/plex_meta_manager.py @@ -108,7 +108,7 @@ def start(config_path, is_test=False, time_scheduled=None, requested_collections logger.info(util.centered("| __/| | __/> < | | | | __/ || (_| | | | | | (_| | | | | (_| | (_| | __/ | ")) logger.info(util.centered("|_| |_|\\___/_/\\_\\ |_| |_|\\___|\\__\\__,_| |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_| ")) logger.info(util.centered(" |___/ ")) - logger.info(util.centered(" Version: 1.11.3-beta5 ")) + logger.info(util.centered(" Version: 1.12.0 ")) if time_scheduled: start_type = f"{time_scheduled} " elif is_test: start_type = "Test " elif requested_collections: start_type = "Collections " @@ -474,7 +474,7 @@ def run_collection(config, library, metadata, requested_collections): util.separator(f"Validating {mapping_name} Attributes", space=False, border=False) - builder = CollectionBuilder(config, library, metadata, mapping_name, collection_attrs) + builder = CollectionBuilder(config, library, metadata, mapping_name, no_missing, collection_attrs) logger.info("") util.separator(f"Building {mapping_name} Collection", space=False, border=False) @@ -495,16 +495,14 @@ def run_collection(config, library, metadata, requested_collections): for filter_key, filter_value in builder.filters: logger.info(f"Collection Filter {filter_key}: {filter_value}") - builder.find_rating_keys(no_missing) + builder.find_rating_keys() if len(builder.rating_keys) > 0 and builder.build_collection: logger.info("") util.separator(f"Adding to {mapping_name} Collection", space=False, border=False) logger.info("") builder.add_to_collection() - if (builder.details["show_missing"] or builder.details["save_missing"] - or (library.Radarr and builder.add_to_radarr) or (library.Sonarr and builder.add_to_sonarr)) \ - and (len(builder.missing_movies) > 0 or len(builder.missing_shows) > 0) and not no_missing: + if builder.do_missing and (len(builder.missing_movies) > 0 or len(builder.missing_shows) > 0): if builder.details["show_missing"] is True: logger.info("") util.separator(f"Missing from Library", space=False, border=False) diff --git a/requirements.txt b/requirements.txt index b8f6cf3f..847af976 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,5 +7,4 @@ ruamel.yaml==0.17.10 schedule==1.1.0 retrying==1.3.3 pathvalidate==2.4.1 -pillow==8.3.1 -python-slugify==5.0.2 \ No newline at end of file +pillow==8.3.1 \ No newline at end of file