diff --git a/modules/builder.py b/modules/builder.py index 2af3b00b..12a3b997 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -303,8 +303,8 @@ class CollectionBuilder: elif method_name in util.dictionary_lists: if isinstance(data[m], dict): def get_int(parent, method, data_in, default_in, minimum=1, maximum=None): - if method not in data_in: logger.warning(f"Collection Warning: {parent} {method} attribute not found using {default} as default") - elif not data_in[method]: logger.warning(f"Collection Warning: {parent} {method} attribute is blank using {default} as default") + if method not in data_in: logger.warning(f"Collection Warning: {parent} {method} attribute not found using {default} as default") + elif not data_in[method]: logger.warning(f"Collection Warning: {parent} {method} attribute is blank using {default} as default") elif isinstance(data_in[method], int) and data_in[method] >= minimum: if maximum is None or data_in[method] <= maximum: return data_in[method] else: logger.warning(f"Collection Warning: {parent} {method} attribute {data_in[method]} invalid must an integer <= {maximum} using {default} as default") @@ -322,19 +322,24 @@ class CollectionBuilder: elif data[m][f] is None: raise Failed(f"Collection Error: {filter_method} filter is blank") elif filter_method == "year": - self.filters.append((filter_method, util.get_year_list(data[m][f], f"{filter_method} filter"))) - elif filter_method in ["max_age", "duration.gte", "duration.lte"]: - self.filters.append((filter_method, util.check_number(data[m][f], f"{filter_method} filter", minimum=1))) + filter_data = util.get_year_list(data[m][f], f"{filter_method} filter") + elif filter_method in ["max_age", "duration.gte", "duration.lte", "tmdb_vote_count.gte", "tmdb_vote_count.lte"]: + filter_data = util.check_number(data[m][f], f"{filter_method} filter", minimum=1) elif filter_method in ["year.gte", "year.lte"]: - self.filters.append((filter_method, util.check_number(data[m][f], f"{filter_method} filter", minimum=1800, maximum=current_year))) + filter_data = util.check_number(data[m][f], f"{filter_method} filter", minimum=1800, maximum=current_year) elif filter_method in ["rating.gte", "rating.lte"]: - self.filters.append((filter_method, util.check_number(data[m][f], f"{filter_method} filter", number_type="float", minimum=0.1, maximum=10))) + filter_data = util.check_number(data[m][f], f"{filter_method} filter", number_type="float", minimum=0.1, maximum=10) elif filter_method in ["originally_available.gte", "originally_available.lte"]: - self.filters.append((filter_method, util.check_date(data[m][f], f"{filter_method} filter"))) + filter_data = util.check_date(data[m][f], f"{filter_method} filter") + elif filter_method == "original_language": + filter_data = util.get_list(data[m][f], lower=True) + elif filter_method == "collection": + filter_data = data[m][f] if isinstance(data[m][f], list) else [data[m][f]] elif filter_method in util.all_filters: - self.filters.append((filter_method, data[m][f])) + filter_data = util.get_list(data[m][f]) else: raise Failed(f"Collection Error: {filter_method} filter not supported") + self.filters.append((filter_method, filter_data)) elif method_name == "plex_collectionless": new_dictionary = {} prefix_list = [] @@ -613,28 +618,32 @@ class CollectionBuilder: if len(missing_movies) > 0 or len(missing_shows) > 0: logger.info("") + arr_filters = [] + for filter_method, filter_data in self.filters: + if (filter_method.startswith("original_language") and self.library.is_movie) or filter_method.startswith("tmdb_vote_count"): + arr_filters.append((filter_method, filter_data)) if len(missing_movies) > 0: - not_lang = None - terms = None - for filter_method, filter_data in self.filters: - if filter_method.startswith("original_language"): - terms = util.get_list(filter_data, lower=True) - not_lang = filter_method.endswith(".not") - break - missing_movies_with_names = [] for missing_id in missing_movies: try: movie = self.config.TMDb.get_movie(missing_id) - title = str(movie.title) - if not_lang is None or (not_lang is True and movie.original_language not in terms) or (not_lang is False and movie.original_language in terms): - missing_movies_with_names.append((title, missing_id)) - if self.details["show_missing"] is True: - logger.info(f"{collection_name} Collection | ? | {title} (TMDb: {missing_id})") - elif self.details["show_filtered"] is True: - logger.info(f"{collection_name} Collection | X | {title} (TMDb: {missing_id})") except Failed as e: logger.error(e) + continue + match = True + for filter_method, filter_data in arr_filters: + if (filter_method == "original_language" and movie.original_language not in filter_data) \ + or (filter_method == "original_language.not" and movie.original_language in filter_data) \ + or (filter_method == "tmdb_vote_count.gte" and movie.vote_count < filter_data) \ + or (filter_method == "tmdb_vote_count.lte" and movie.vote_count > filter_data): + match = False + break + if match: + missing_movies_with_names.append((movie.title, missing_id)) + if self.details["show_missing"] is True: + logger.info(f"{collection_name} Collection | ? | {movie.title} (TMDb: {missing_id})") + elif self.details["show_filtered"] is True: + logger.info(f"{collection_name} Collection | X | {movie.title} (TMDb: {missing_id})") logger.info(f"{len(missing_movies_with_names)} Movie{'s' if len(missing_movies_with_names) > 1 else ''} Missing") if self.details["save_missing"] is True: self.library.add_missing(collection_name, missing_movies_with_names, True) @@ -645,11 +654,23 @@ class CollectionBuilder: for missing_id in missing_shows: try: title = str(self.config.TVDb.get_series(self.library.Plex.language, tvdb_id=missing_id).title.encode("ascii", "replace").decode()) + except Failed as e: + logger.error(e) + continue + match = True + if arr_filters: + show = self.config.TMDb.get_show(self.config.TMDb.convert_tvdb_to_tmdb(missing_id)) + for filter_method, filter_data in arr_filters: + if (filter_method == "tmdb_vote_count.gte" and show.vote_count < filter_data) \ + or (filter_method == "tmdb_vote_count.lte" and show.vote_count > filter_data): + match = False + break + if match: missing_shows_with_names.append((title, missing_id)) if self.details["show_missing"] is True: logger.info(f"{collection_name} Collection | ? | {title} (TVDB: {missing_id})") - except Failed as e: - logger.error(e) + elif self.details["show_filtered"] is True: + logger.info(f"{collection_name} Collection | X | {title} (TMDb: {missing_id})") logger.info(f"{len(missing_shows_with_names)} Show{'s' if len(missing_shows_with_names) > 1 else ''} Missing") if self.details["save_missing"] is True: self.library.add_missing(collection_name, missing_shows_with_names, False) diff --git a/modules/plex.py b/modules/plex.py index 276ba2e0..21aa69cf 100644 --- a/modules/plex.py +++ b/modules/plex.py @@ -135,16 +135,15 @@ class PlexAPI: match = True if filters: length = util.print_return(length, f"Filtering {(' ' * (max_length - len(str(i)))) + str(i)}/{total} {current.title}") - for f in filters: - modifier = f[0][-4:] - method = util.filter_alias[f[0][:-4]] if modifier in [".not", ".lte", ".gte"] else util.filter_alias[f[0]] + for filter_method, filter_data in filters: + modifier = filter_method[-4:] + method = util.filter_alias[filter_method[:-4]] if modifier in [".not", ".lte", ".gte"] else util.filter_alias[filter_method] if method == "max_age": - threshold_date = datetime.now() - timedelta(days=f[1]) + threshold_date = datetime.now() - timedelta(days=filter_data) if current.originallyAvailableAt is None or current.originallyAvailableAt < threshold_date: match = False break elif method == "original_language": - terms = util.get_list(f[1], lower=True) movie = None for key, value in movie_map.items(): if current.ratingKey == value: @@ -156,18 +155,29 @@ class PlexAPI: if movie is None: logger.warning(f"Filter Error: No TMDb ID found for {current.title}") continue - if (modifier == ".not" and movie.original_language in terms) or (modifier != ".not" and movie.original_language not in terms): + if (modifier == ".not" and movie.original_language in filter_data) or (modifier != ".not" and movie.original_language not in filter_data): match = False break elif modifier in [".gte", ".lte"]: - attr = getattr(current, method) - if method == "duration": - attr = attr / 60000 - if (modifier == ".lte" and attr > f[1]) or (modifier == ".gte" and attr < f[1]): + if method == "vote_count": + tmdb_item = None + for key, value in movie_map.items(): + if current.ratingKey == value: + try: + tmdb_item = self.TMDb.get_movie(key) if self.is_movie else self.TMDb.get_show(key) + break + except Failed: + pass + if tmdb_item is None: + logger.warning(f"Filter Error: No TMDb ID found for {current.title}") + continue + attr = tmdb_item.vote_count + else: + attr = getattr(current, method) / 60000 if method == "duration" else getattr(current, method) + if (modifier == ".lte" and attr > filter_data) or (modifier == ".gte" and attr < filter_data): match = False break else: - terms = util.get_list(f[1]) attrs = [] if method in ["video_resolution", "audio_language", "subtitle_language"]: for media in current.media: @@ -178,7 +188,7 @@ class PlexAPI: elif method in ["contentRating", "studio", "year", "rating", "originallyAvailableAt"]: attrs = [str(getattr(current, method))] elif method in ["actors", "countries", "directors", "genres", "writers", "collections"]: attrs = [getattr(x, "tag") for x in getattr(current, method)] - if (not list(set(terms) & set(attrs)) and modifier != ".not") or (list(set(terms) & set(attrs)) and modifier == ".not"): + if (not list(set(filter_data) & set(attrs)) and modifier != ".not") or (list(set(filter_data) & set(attrs)) and modifier == ".not"): match = False break length = util.print_return(length, f"Filtering {(' ' * (max_length - len(str(i)))) + str(i)}/{total} {current.title}") diff --git a/modules/util.py b/modules/util.py index 19b91596..6ae244ab 100644 --- a/modules/util.py +++ b/modules/util.py @@ -48,6 +48,7 @@ filter_alias = { "rating": "rating", "studio": "studio", "subtitle_language": "subtitle_language", + "tmdb_vote_count": "vote_count", "writer": "writers", "video_resolution": "video_resolution", "year": "year" @@ -390,6 +391,7 @@ all_filters = [ "genre", "genre.not", "max_age", "originally_available.gte", "originally_available.lte", + "tmdb_vote_count.gte", "tmdb_vote_count.lte", "duration.gte", "duration.lte", "original_language", "original_language.not", "rating.gte", "rating.lte",