mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-13 00:07:13 +00:00
updated filters
This commit is contained in:
parent
5c89ee5478
commit
b0fa4a64a0
2 changed files with 130 additions and 118 deletions
|
@ -25,11 +25,12 @@ method_alias = {
|
||||||
"labels": "label",
|
"labels": "label",
|
||||||
"rating": "critic_rating",
|
"rating": "critic_rating",
|
||||||
"show_user_rating": "user_rating",
|
"show_user_rating": "user_rating",
|
||||||
|
"video_resolution": "resolution",
|
||||||
"play": "plays", "show_plays": "plays", "show_play": "plays", "episode_play": "episode_plays",
|
"play": "plays", "show_plays": "plays", "show_play": "plays", "episode_play": "episode_plays",
|
||||||
"originally_available": "release", "episode_originally_available": "episode_air_date",
|
"originally_available": "release", "episode_originally_available": "episode_air_date",
|
||||||
"episode_release": "episode_air_date", "episode_released": "episode_air_date",
|
"episode_release": "episode_air_date", "episode_released": "episode_air_date",
|
||||||
"show_originally_available": "release", "show_release": "release", "show_air_date": "release",
|
"show_originally_available": "release", "show_release": "release", "show_air_date": "release",
|
||||||
"released": "release", "show_released": "release",
|
"released": "release", "show_released": "release", "max_age": "release",
|
||||||
"studios": "studio",
|
"studios": "studio",
|
||||||
"networks": "network",
|
"networks": "network",
|
||||||
"producers": "producer",
|
"producers": "producer",
|
||||||
|
@ -49,7 +50,9 @@ filter_translation = {
|
||||||
"label": "labels",
|
"label": "labels",
|
||||||
"producer": "producers",
|
"producer": "producers",
|
||||||
"release": "originallyAvailableAt",
|
"release": "originallyAvailableAt",
|
||||||
"tmdb_vote_count": "vote_count",
|
"added": "addedAt",
|
||||||
|
"last_played": "lastViewedAt",
|
||||||
|
"plays": "viewCount",
|
||||||
"user_rating": "userRating",
|
"user_rating": "userRating",
|
||||||
"writer": "writers"
|
"writer": "writers"
|
||||||
}
|
}
|
||||||
|
@ -155,27 +158,31 @@ boolean_details = [
|
||||||
all_filters = [
|
all_filters = [
|
||||||
"actor", "actor.not",
|
"actor", "actor.not",
|
||||||
"audio_language", "audio_language.not",
|
"audio_language", "audio_language.not",
|
||||||
"audio_track_title", "audio_track_title.not",
|
"audio_track_title", "audio_track_title.not", "audio_track_title.begins", "audio_track_title.ends",
|
||||||
"collection", "collection.not",
|
"collection", "collection.not",
|
||||||
"content_rating", "content_rating.not",
|
"content_rating", "content_rating.not",
|
||||||
"country", "country.not",
|
"country", "country.not",
|
||||||
"director", "director.not",
|
"director", "director.not",
|
||||||
"filepath", "filepath.not",
|
"filepath", "filepath.not",
|
||||||
"genre", "genre.not",
|
"genre", "genre.not",
|
||||||
"max_age",
|
"label", "label.not",
|
||||||
"release.gte", "release.lte",
|
"producer", "producer.not",
|
||||||
"title", "title.not",
|
"release", "release.not", "release.before", "release.after",
|
||||||
"tmdb_vote_count.gte", "tmdb_vote_count.lte",
|
"added", "added.not", "added.before", "added.after",
|
||||||
"duration.gte", "duration.lte",
|
"last_played", "last_played.not", "last_played.before", "last_played.after",
|
||||||
|
"title", "title.not", "title.begins", "title.ends",
|
||||||
|
"plays.gt", "plays.gte", "plays.lt", "plays.lte",
|
||||||
|
"tmdb_vote_count.gt", "tmdb_vote_count.gte", "tmdb_vote_count.lt", "tmdb_vote_count.lte",
|
||||||
|
"duration.gt", "duration.gte", "duration.lt", "duration.lte",
|
||||||
"original_language", "original_language.not",
|
"original_language", "original_language.not",
|
||||||
"user_rating.gte", "user_rating.lte",
|
"user_rating.gt", "user_rating.gte", "user_rating.lt", "user_rating.lte",
|
||||||
"audience_rating.gte", "audience_rating.lte",
|
"audience_rating.gt", "audience_rating.gte", "audience_rating.lt", "audience_rating.lte",
|
||||||
"critic_rating.gte", "critic_rating.lte",
|
"critic_rating.gt", "critic_rating.gte", "critic_rating.lt", "critic_rating.lte",
|
||||||
"studio", "studio.not",
|
"studio", "studio.not", "studio.begins", "studio.ends",
|
||||||
"subtitle_language", "subtitle_language.not",
|
"subtitle_language", "subtitle_language.not",
|
||||||
"video_resolution", "video_resolution.not",
|
"resolution", "resolution.not",
|
||||||
"writer", "writer.not",
|
"writer", "writer.not",
|
||||||
"year", "year.gte", "year.lte", "year.not"
|
"year", "year.gt", "year.gte", "year.lt", "year.lte", "year.not"
|
||||||
]
|
]
|
||||||
movie_only_filters = [
|
movie_only_filters = [
|
||||||
"audio_language", "audio_language.not",
|
"audio_language", "audio_language.not",
|
||||||
|
@ -185,9 +192,10 @@ movie_only_filters = [
|
||||||
"duration.gte", "duration.lte",
|
"duration.gte", "duration.lte",
|
||||||
"original_language", "original_language.not",
|
"original_language", "original_language.not",
|
||||||
"subtitle_language", "subtitle_language.not",
|
"subtitle_language", "subtitle_language.not",
|
||||||
"video_resolution", "video_resolution.not",
|
"resolution", "resolution.not",
|
||||||
"writer", "writer.not"
|
"writer", "writer.not"
|
||||||
]
|
]
|
||||||
|
show_only_filters = ["network"]
|
||||||
|
|
||||||
class CollectionBuilder:
|
class CollectionBuilder:
|
||||||
def __init__(self, config, library, metadata, name, data):
|
def __init__(self, config, library, metadata, name, data):
|
||||||
|
@ -588,13 +596,13 @@ class CollectionBuilder:
|
||||||
validation = self.validate_attribute(smart, smart_mod, smart_final, smart_data, validate, smart=True)
|
validation = self.validate_attribute(smart, smart_mod, smart_final, smart_data, validate, smart=True)
|
||||||
if validation is None:
|
if validation is None:
|
||||||
continue
|
continue
|
||||||
elif smart in plex.date_searches and smart_mod in ["", ".not"]:
|
elif smart in plex.date_attributes and smart_mod in ["", ".not"]:
|
||||||
last_text = "is not in the last" if smart_mod == ".not" else "is in the last"
|
last_text = "is not in the last" if smart_mod == ".not" else "is in the last"
|
||||||
last_mod = "%3E%3E" if smart_mod == "" else "%3C%3C"
|
last_mod = "%3E%3E" if smart_mod == "" else "%3C%3C"
|
||||||
results, display_add = build_url_arg(f"-{validation}d", mod=last_mod, arg_s=f"{validation} Days", mod_s=last_text)
|
results, display_add = build_url_arg(f"-{validation}d", mod=last_mod, arg_s=f"{validation} Days", mod_s=last_text)
|
||||||
elif smart == "duration" and smart_mod in [".gt", ".gte", ".lt", ".lte"]:
|
elif smart == "duration" and smart_mod in [".gt", ".gte", ".lt", ".lte"]:
|
||||||
results, display_add = build_url_arg(validation * 60000)
|
results, display_add = build_url_arg(validation * 60000)
|
||||||
elif smart in plex.boolean_searches:
|
elif smart in plex.boolean_attributes:
|
||||||
bool_mod = "" if validation else "!"
|
bool_mod = "" if validation else "!"
|
||||||
bool_arg = "true" if validation else "false"
|
bool_arg = "true" if validation else "false"
|
||||||
results, display_add = build_url_arg(1, mod=bool_mod, arg_s=bool_arg, mod_s="is")
|
results, display_add = build_url_arg(1, mod=bool_mod, arg_s=bool_arg, mod_s="is")
|
||||||
|
@ -862,40 +870,25 @@ class CollectionBuilder:
|
||||||
logger.warning(f"Collection Warning: {parent} {methods_in[int_method]} attribute {data_in[methods_in[int_method]]} invalid must an integer >= {minimum} using {default_in} as default")
|
logger.warning(f"Collection Warning: {parent} {methods_in[int_method]} attribute {data_in[methods_in[int_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 filter_name, filter_data in method_data.items():
|
validate = True
|
||||||
modifier = filter_name[-4:].lower()
|
if "validate" in method_data:
|
||||||
modifier = modifier if modifier in [".not", ".lte", ".gte"] else ""
|
if method_data["validate"] is None:
|
||||||
method = filter_name[:-4].lower() if modifier in [".not", ".lte", ".gte"] else filter_name.lower()
|
raise Failed("Collection Error: validate filter attribute is blank")
|
||||||
if method in method_alias:
|
if not isinstance(method_data["validate"], bool):
|
||||||
filter_method = f"{method_alias[method]}{modifier}"
|
raise Failed("Collection Error: validate filter attribute must be either true or false")
|
||||||
logger.warning(f"Collection Warning: {filter_name} filter will run as {filter_method}")
|
validate = method_data["validate"]
|
||||||
|
for filter_method, filter_data in method_data.items():
|
||||||
|
filter_attr, modifier, filter_final = self._split(filter_method)
|
||||||
|
if filter_final not in all_filters:
|
||||||
|
raise Failed(f"Collection Error: {filter_final} is not a valid filter attribute")
|
||||||
|
elif filter_final in movie_only_filters and self.library.is_show:
|
||||||
|
raise Failed(f"Collection Error: {filter_final} filter attribute only works for movie libraries")
|
||||||
|
elif filter_final in show_only_filters and self.library.is_movie:
|
||||||
|
raise Failed(f"Collection Error: {filter_final} filter attribute only works for show libraries")
|
||||||
|
elif filter_final is None:
|
||||||
|
raise Failed(f"Collection Error: {filter_final} filter attribute is blank")
|
||||||
else:
|
else:
|
||||||
filter_method = f"{method}{modifier}"
|
self.filters.append((filter_final, self.validate_attribute(filter_attr, modifier, f"{filter_final} filter", filter_data, validate)))
|
||||||
if filter_method in movie_only_filters and self.library.is_show:
|
|
||||||
raise Failed(f"Collection Error: {filter_method} filter only works for movie libraries")
|
|
||||||
elif filter_data is None:
|
|
||||||
raise Failed(f"Collection Error: {filter_method} filter is blank")
|
|
||||||
elif filter_method == "year":
|
|
||||||
valid_data = util.get_year_list(filter_data, self.current_year, f"{filter_method} filter")
|
|
||||||
elif filter_method in ["max_age", "duration.gte", "duration.lte", "tmdb_vote_count.gte", "tmdb_vote_count.lte"]:
|
|
||||||
valid_data = util.check_number(filter_data, f"{filter_method} filter", minimum=1)
|
|
||||||
elif filter_method in ["year.gte", "year.lte"]:
|
|
||||||
valid_data = util.check_year(filter_data, self.current_year, f"{filter_method} filter")
|
|
||||||
elif filter_method in ["user_rating.gte", "user_rating.lte", "audience_rating.gte", "audience_rating.lte", "critic_rating.gte", "critic_rating.lte"]:
|
|
||||||
valid_data = util.check_number(filter_data, f"{filter_method} filter", number_type="float", minimum=0.1, maximum=10)
|
|
||||||
elif filter_method in ["release.gte", "release.lte"]:
|
|
||||||
valid_data = util.check_date(filter_data, f"{filter_method} filter")
|
|
||||||
elif filter_method in ["original_language", "original_language.not"]:
|
|
||||||
valid_data = util.get_list(filter_data, lower=True)
|
|
||||||
elif filter_method in ["collection", "collection.not"]:
|
|
||||||
valid_data = filter_data if isinstance(filter_data, list) else [filter_data]
|
|
||||||
elif filter_method in ["title", "title.not"]:
|
|
||||||
valid_data = util.get_list(filter_data, split=False)
|
|
||||||
elif filter_method in all_filters:
|
|
||||||
valid_data = util.get_list(filter_data)
|
|
||||||
else:
|
|
||||||
raise Failed(f"Collection Error: {filter_method} filter not supported")
|
|
||||||
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 method_data}
|
dict_methods = {dm.lower(): dm for dm in method_data}
|
||||||
|
@ -928,7 +921,9 @@ class CollectionBuilder:
|
||||||
validate = method_data["validate"]
|
validate = method_data["validate"]
|
||||||
for search_name, search_data in method_data.items():
|
for search_name, search_data in method_data.items():
|
||||||
search, modifier, search_final = self._split(search_name)
|
search, modifier, search_final = self._split(search_name)
|
||||||
if search_final in plex.movie_only_searches and self.library.is_show:
|
if search_final not in plex.searches:
|
||||||
|
raise Failed(f"Collection Error: {search_final} is not a valid plex search attribute")
|
||||||
|
elif search_final in plex.movie_only_searches and self.library.is_show:
|
||||||
raise Failed(f"Collection Error: {search_final} plex search attribute only works for movie libraries")
|
raise Failed(f"Collection Error: {search_final} plex search attribute only works for movie libraries")
|
||||||
elif search_final in plex.show_only_searches and self.library.is_movie:
|
elif search_final in plex.show_only_searches and self.library.is_movie:
|
||||||
raise Failed(f"Collection Error: {search_final} plex search attribute only works for show libraries")
|
raise Failed(f"Collection Error: {search_final} plex search attribute only works for show libraries")
|
||||||
|
@ -946,8 +941,6 @@ class CollectionBuilder:
|
||||||
raise Failed(f"Collection Warning: plex search limit attribute: {search_data} must be an integer greater then 0")
|
raise Failed(f"Collection Warning: plex search limit attribute: {search_data} must be an integer greater then 0")
|
||||||
else:
|
else:
|
||||||
searches[search] = search_data
|
searches[search] = search_data
|
||||||
elif search_final not in plex.searches:
|
|
||||||
raise Failed(f"Collection Error: {search_final} is not a valid plex search attribute")
|
|
||||||
else:
|
else:
|
||||||
searches[search_final] = self.validate_attribute(search, modifier, search_final, search_data, validate)
|
searches[search_final] = self.validate_attribute(search, modifier, search_final, search_data, validate)
|
||||||
if len(searches) > 0:
|
if len(searches) > 0:
|
||||||
|
@ -1277,10 +1270,14 @@ class CollectionBuilder:
|
||||||
def validate_attribute(self, attribute, modifier, final, data, validate, smart=False):
|
def validate_attribute(self, attribute, modifier, final, data, validate, smart=False):
|
||||||
def smart_pair(list_to_pair):
|
def smart_pair(list_to_pair):
|
||||||
return [(t, t) for t in list_to_pair] if smart else list_to_pair
|
return [(t, t) for t in list_to_pair] if smart else list_to_pair
|
||||||
if attribute in ["title", "studio", "episode_title"] and modifier in ["", ".and", ".not", ".begins", ".ends"]:
|
if attribute in ["title", "studio", "episode_title", "audio_track_title"] and modifier in ["", ".and", ".not", ".begins", ".ends"]:
|
||||||
return smart_pair(util.get_list(data, split=False))
|
return smart_pair(util.get_list(data, split=False))
|
||||||
elif attribute in plex.tags and modifier in ["", ".and", ".not", ".begins", ".ends"]:
|
elif attribute == "original_language":
|
||||||
if final in plex.tmdb_searches:
|
return util.get_list(data, lower=True)
|
||||||
|
elif attribute == "filepath":
|
||||||
|
return util.get_list(data)
|
||||||
|
elif attribute in plex.tags and modifier in ["", ".and", ".not"]:
|
||||||
|
if attribute in plex.tmdb_attributes:
|
||||||
final_values = []
|
final_values = []
|
||||||
for value in util.get_list(data):
|
for value in util.get_list(data):
|
||||||
if value.lower() == "tmdb" and "tmdb_person" in self.details:
|
if value.lower() == "tmdb" and "tmdb_person" in self.details:
|
||||||
|
@ -1299,18 +1296,18 @@ class CollectionBuilder:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
elif attribute in ["year", "episode_year"] and modifier in [".gt", ".gte", ".lt", ".lte"]:#
|
elif attribute in ["year", "episode_year"] and modifier in [".gt", ".gte", ".lt", ".lte"]:#
|
||||||
return util.check_year(data, self.current_year, final)
|
return util.check_year(data, self.current_year, final)
|
||||||
elif attribute in ["added", "episode_added", "release", "episode_air_date"] and modifier in [".before", ".after"]:#
|
elif attribute in plex.date_attributes and modifier in [".before", ".after"]:#
|
||||||
return util.check_date(data, final, return_string=True, plex_date=True)
|
return util.check_date(data, final, return_string=True, plex_date=True)
|
||||||
elif attribute in ["plays", "episode_plays", "added", "episode_added", "release", "episode_air_date", "duration"] and modifier in ["", ".not", ".gt", ".gte", ".lt", ".lte"]:
|
elif attribute in plex.number_attributes and modifier in ["", ".not", ".gt", ".gte", ".lt", ".lte"]:
|
||||||
return util.check_number(data, final, minimum=1)
|
return util.check_number(data, final, minimum=1)
|
||||||
elif attribute in ["user_rating", "episode_user_rating", "critic_rating", "audience_rating"] and modifier in [".gt", ".gte", ".lt", ".lte"]:
|
elif attribute in plex.float_attributes and modifier in [".gt", ".gte", ".lt", ".lte"]:
|
||||||
return util.check_number(data, final, number_type="float", minimum=0, maximum=10)
|
return util.check_number(data, final, number_type="float", minimum=0, maximum=10)
|
||||||
elif attribute in ["decade", "year", "episode_year"] and modifier in ["", ".not"]:
|
elif attribute in ["decade", "year", "episode_year"] and modifier in ["", ".not"]:
|
||||||
return smart_pair(util.get_year_list(data, self.current_year, final))
|
return smart_pair(util.get_year_list(data, self.current_year, final))
|
||||||
elif attribute in plex.boolean_searches:
|
elif attribute in plex.boolean_attributes:
|
||||||
return util.get_bool(attribute, data)
|
return util.get_bool(attribute, data)
|
||||||
else:
|
else:
|
||||||
raise Failed(f"Collection Error: modifier: {modifier} not supported with the {attribute} attribute")
|
raise Failed(f"Collection Error: {final} attribute not supported")
|
||||||
|
|
||||||
def _split(self, text):
|
def _split(self, text):
|
||||||
attribute, modifier = os.path.splitext(str(text).lower())
|
attribute, modifier = os.path.splitext(str(text).lower())
|
||||||
|
@ -1363,23 +1360,50 @@ class CollectionBuilder:
|
||||||
def check_filters(self, current, display):
|
def check_filters(self, current, display):
|
||||||
if self.filters:
|
if self.filters:
|
||||||
util.print_return(f"Filtering {display} {current.title}")
|
util.print_return(f"Filtering {display} {current.title}")
|
||||||
|
current_date = datetime.now()
|
||||||
for filter_method, filter_data in self.filters:
|
for filter_method, filter_data in self.filters:
|
||||||
modifier = filter_method[-4:]
|
filter_attr, modifier, filter_final = self._split(filter_method)
|
||||||
method = filter_method[:-4] if modifier in [".not", ".lte", ".gte"] else filter_method
|
filter_actual = filter_translation[filter_attr] if filter_attr in filter_translation else filter_attr
|
||||||
method_name = filter_translation[method] if method in filter_translation else method
|
if filter_attr in ["release", "added", "last_played"]:
|
||||||
if method_name == "max_age":
|
current_data = getattr(current, filter_actual)
|
||||||
threshold_date = datetime.now() - timedelta(days=filter_data)
|
if modifier in ["", ".not"]:
|
||||||
if current.originallyAvailableAt is None or current.originallyAvailableAt < threshold_date:
|
threshold_date = current_date - timedelta(days=filter_data)
|
||||||
return False
|
if (modifier == "" and (current_data is None or current_data < threshold_date)) \
|
||||||
elif method_name == "title":
|
or (modifier == ".not" and current_data and current_data >= threshold_date):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if (modifier == ".before" and (current_data is None or current_data >= filter_data)) \
|
||||||
|
or (modifier == ".after" and (current_data is None or current_data <= filter_data)):
|
||||||
|
return False
|
||||||
|
elif filter_attr == "audio_track_title":
|
||||||
jailbreak = False
|
jailbreak = False
|
||||||
for check_title in filter_data:
|
for media in current.media:
|
||||||
if check_title.lower() in current.title.lower():
|
for part in media.parts:
|
||||||
|
for audio in part.audioStreams():
|
||||||
|
for check_title in filter_data:
|
||||||
|
title = audio.title if audio.title else ""
|
||||||
|
if (modifier in ["", ".not"] and check_title.lower() in title.lower()) \
|
||||||
|
or (modifier == ".begins" and title.lower().startswith(check_title.lower())) \
|
||||||
|
or (modifier == ".ends" and title.lower().endswith(check_title.lower())):
|
||||||
|
jailbreak = True
|
||||||
|
break
|
||||||
|
if jailbreak: break
|
||||||
|
if jailbreak: break
|
||||||
|
if jailbreak: break
|
||||||
|
if (jailbreak and modifier == ".not") or (not jailbreak and modifier in ["", ".begins", ".ends"]):
|
||||||
|
return False
|
||||||
|
elif filter_attr in ["title", "studio"]:
|
||||||
|
jailbreak = False
|
||||||
|
current_data = getattr(current, filter_actual)
|
||||||
|
for check_data in filter_data:
|
||||||
|
if (modifier in ["", ".not"] and check_data.lower() in current_data.lower()) \
|
||||||
|
or (modifier == ".begins" and current_data.lower().startswith(check_data.lower())) \
|
||||||
|
or (modifier == ".ends" and current_data.lower().endswith(check_data.lower())):
|
||||||
jailbreak = True
|
jailbreak = True
|
||||||
break
|
break
|
||||||
if (jailbreak and modifier == ".not") or (not jailbreak and modifier != ".not"):
|
if (jailbreak and modifier == ".not") or (not jailbreak and modifier in ["", ".begins", ".ends"]):
|
||||||
return False
|
return False
|
||||||
elif method_name == "original_language":
|
elif filter_attr == "original_language":
|
||||||
movie = None
|
movie = None
|
||||||
for key, value in self.library.movie_map.items():
|
for key, value in self.library.movie_map.items():
|
||||||
if current.ratingKey in value:
|
if current.ratingKey in value:
|
||||||
|
@ -1391,24 +1415,10 @@ class CollectionBuilder:
|
||||||
if movie is None:
|
if movie is None:
|
||||||
logger.warning(f"Filter Error: No TMDb ID found for {current.title}")
|
logger.warning(f"Filter Error: No TMDb ID found for {current.title}")
|
||||||
continue
|
continue
|
||||||
if (modifier == ".not" and movie.original_language in filter_data) or (modifier != ".not" and movie.original_language not in filter_data):
|
if (modifier == ".not" and movie.original_language in filter_data) \
|
||||||
|
or (modifier == "" and movie.original_language not in filter_data):
|
||||||
return False
|
return False
|
||||||
elif method_name == "audio_track_title":
|
elif filter_attr == "filepath":
|
||||||
jailbreak = False
|
|
||||||
for media in current.media:
|
|
||||||
for part in media.parts:
|
|
||||||
for audio in part.audioStreams():
|
|
||||||
for check_title in filter_data:
|
|
||||||
title = audio.title if audio.title else ""
|
|
||||||
if check_title.lower() in title.lower():
|
|
||||||
jailbreak = True
|
|
||||||
break
|
|
||||||
if jailbreak: break
|
|
||||||
if jailbreak: break
|
|
||||||
if jailbreak: break
|
|
||||||
if (jailbreak and modifier == ".not") or (not jailbreak and modifier != ".not"):
|
|
||||||
return False
|
|
||||||
elif method_name == "filepath":
|
|
||||||
jailbreak = False
|
jailbreak = False
|
||||||
for location in current.locations:
|
for location in current.locations:
|
||||||
for check_text in filter_data:
|
for check_text in filter_data:
|
||||||
|
@ -1416,16 +1426,15 @@ class CollectionBuilder:
|
||||||
jailbreak = True
|
jailbreak = True
|
||||||
break
|
break
|
||||||
if jailbreak: break
|
if jailbreak: break
|
||||||
if (jailbreak and modifier == ".not") or (not jailbreak and modifier != ".not"):
|
if (jailbreak and modifier == ".not") or (not jailbreak and modifier == ""):
|
||||||
return False
|
return False
|
||||||
elif modifier in [".gte", ".lte"]:
|
elif modifier in [".gt", ".gte", ".lt", ".lte"]:
|
||||||
if method_name == "vote_count":
|
if filter_attr == "tmdb_vote_count":
|
||||||
tmdb_item = None
|
tmdb_item = None
|
||||||
for key, value in self.library.movie_map.items():
|
for key, value in self.library.movie_map.items():
|
||||||
if current.ratingKey in value:
|
if current.ratingKey in value:
|
||||||
try:
|
try:
|
||||||
tmdb_item = self.config.TMDb.get_movie(
|
tmdb_item = self.config.TMDb.get_movie(key) if self.library.is_movie else self.config.TMDb.get_show(key)
|
||||||
key) if self.library.is_movie else self.config.TMDb.get_show(key)
|
|
||||||
break
|
break
|
||||||
except Failed:
|
except Failed:
|
||||||
pass
|
pass
|
||||||
|
@ -1433,29 +1442,35 @@ class CollectionBuilder:
|
||||||
logger.warning(f"Filter Error: No TMDb ID found for {current.title}")
|
logger.warning(f"Filter Error: No TMDb ID found for {current.title}")
|
||||||
continue
|
continue
|
||||||
attr = tmdb_item.vote_count
|
attr = tmdb_item.vote_count
|
||||||
|
elif filter_attr == "duration":
|
||||||
|
attr = getattr(current, filter_actual) / 60000
|
||||||
else:
|
else:
|
||||||
attr = getattr(current, method_name) / 60000 if method_name == "duration" else getattr(current, method_name)
|
attr = getattr(current, filter_actual)
|
||||||
if attr is None or (modifier == ".lte" and attr > filter_data) or (modifier == ".gte" and attr < filter_data):
|
if attr is None or (modifier == ".gt" and attr <= filter_data) \
|
||||||
|
or (modifier == ".gte" and attr < filter_data) \
|
||||||
|
or (modifier == ".lt" and attr >= filter_data) \
|
||||||
|
or (modifier == ".lte" and attr > filter_data):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
attrs = []
|
attrs = []
|
||||||
if method_name in ["video_resolution", "audio_language", "subtitle_language"]:
|
if filter_attr in ["resolution", "audio_language", "subtitle_language"]:
|
||||||
for media in current.media:
|
for media in current.media:
|
||||||
if method_name == "video_resolution":
|
if filter_attr == "resolution":
|
||||||
attrs.extend([media.videoResolution])
|
attrs.extend([media.videoResolution])
|
||||||
for part in media.parts:
|
for part in media.parts:
|
||||||
if method_name == "audio_language":
|
if filter_attr == "audio_language":
|
||||||
attrs.extend([a.language for a in part.audioStreams()])
|
attrs.extend([a.language for a in part.audioStreams()])
|
||||||
if method_name == "subtitle_language":
|
if filter_attr == "subtitle_language":
|
||||||
attrs.extend([s.language for s in part.subtitleStreams()])
|
attrs.extend([s.language for s in part.subtitleStreams()])
|
||||||
elif method_name in ["contentRating", "studio", "year", "rating", "originallyAvailableAt"]:
|
elif filter_attr in ["content_rating", "year", "rating"]:
|
||||||
attrs = [str(getattr(current, method_name))]
|
attrs = [str(getattr(current, filter_actual))]
|
||||||
elif method_name in ["actors", "countries", "directors", "genres", "writers", "collections"]:
|
elif filter_attr in ["actor", "country", "director", "genre", "label", "producer", "writer", "collection"]:
|
||||||
attrs = [getattr(x, "tag") for x in getattr(current, method_name)]
|
attrs = [attr.tag for attr in getattr(current, filter_actual)]
|
||||||
else:
|
else:
|
||||||
raise Failed(f"Filter Error: filter: {method_name} not supported")
|
raise Failed(f"Filter Error: filter: {filter_final} not supported")
|
||||||
|
|
||||||
if (not list(set(filter_data) & set(attrs)) and modifier != ".not") or (list(set(filter_data) & set(attrs)) and modifier == ".not"):
|
if (not list(set(filter_data) & set(attrs)) and modifier == "") \
|
||||||
|
or (list(set(filter_data) & set(attrs)) and modifier == ".not"):
|
||||||
return False
|
return False
|
||||||
util.print_return(f"Filtering {display} {current.title}")
|
util.print_return(f"Filtering {display} {current.title}")
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -129,17 +129,14 @@ show_only_searches = [
|
||||||
"episode_user_rating.gt", "episode_user_rating.gte", "episode_user_rating.lt", "episode_user_rating.lte",
|
"episode_user_rating.gt", "episode_user_rating.gte", "episode_user_rating.lt", "episode_user_rating.lte",
|
||||||
"episode_year", "episode_year.not", "episode_year.gt", "episode_year.gte", "episode_year.lt", "episode_year.lte"
|
"episode_year", "episode_year.not", "episode_year.gt", "episode_year.gte", "episode_year.lt", "episode_year.lte"
|
||||||
]
|
]
|
||||||
tmdb_searches = [
|
number_attributes = ["plays", "episode_plays", "added", "episode_added", "release", "episode_air_date", "duration", "tmdb_vote_count"]
|
||||||
"actor", "actor.and", "actor.not",
|
float_attributes = ["user_rating", "episode_user_rating", "critic_rating", "audience_rating"]
|
||||||
"director", "director.and", "director.not",
|
boolean_attributes = [
|
||||||
"producer", "producer.and", "producer.not",
|
|
||||||
"writer", "writer.and", "writer.not"
|
|
||||||
]
|
|
||||||
boolean_searches = [
|
|
||||||
"hdr", "unmatched", "duplicate", "unplayed", "progress", "trash",
|
"hdr", "unmatched", "duplicate", "unplayed", "progress", "trash",
|
||||||
"unplayed_episodes", "episode_unplayed", "episode_duplicate", "episode_progress", "episode_unmatched",
|
"unplayed_episodes", "episode_unplayed", "episode_duplicate", "episode_progress", "episode_unmatched",
|
||||||
]
|
]
|
||||||
date_searches = ["added", "episode_added", "release", "episode_air_date", "last_played", "episode_last_played"]
|
tmdb_attributes = ["actor", "director", "producer", "writer"]
|
||||||
|
date_attributes = ["added", "episode_added", "release", "episode_air_date", "last_played", "episode_last_played"]
|
||||||
search_display = {
|
search_display = {
|
||||||
"added": "Date Added",
|
"added": "Date Added",
|
||||||
"release": "Release Date",
|
"release": "Release Date",
|
||||||
|
@ -530,9 +527,9 @@ class PlexAPI:
|
||||||
else:
|
else:
|
||||||
search, modifier = os.path.splitext(str(search_method).lower())
|
search, modifier = os.path.splitext(str(search_method).lower())
|
||||||
final_search = search_translation[search] if search in search_translation else search
|
final_search = search_translation[search] if search in search_translation else search
|
||||||
if search in date_searches and modifier == "":
|
if search in date_attributes and modifier == "":
|
||||||
final_mod = ">>"
|
final_mod = ">>"
|
||||||
elif search in date_searches and modifier == ".not":
|
elif search in date_attributes and modifier == ".not":
|
||||||
final_mod = "<<"
|
final_mod = "<<"
|
||||||
elif search in ["critic_rating", "audience_rating"] and modifier == ".gt":
|
elif search in ["critic_rating", "audience_rating"] and modifier == ".gt":
|
||||||
final_mod = "__gt"
|
final_mod = "__gt"
|
||||||
|
@ -544,7 +541,7 @@ class PlexAPI:
|
||||||
|
|
||||||
if search == "duration":
|
if search == "duration":
|
||||||
search_terms[final_method] = search_data * 60000
|
search_terms[final_method] = search_data * 60000
|
||||||
elif search in date_searches and modifier in ["", ".not"]:
|
elif search in date_attributes and modifier in ["", ".not"]:
|
||||||
search_terms[final_method] = f"{search_data}d"
|
search_terms[final_method] = f"{search_data}d"
|
||||||
else:
|
else:
|
||||||
search_terms[final_method] = search_data
|
search_terms[final_method] = search_data
|
||||||
|
|
Loading…
Reference in a new issue