mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
#66 filter by duration and filter validation
This commit is contained in:
parent
a43e2a26d9
commit
c25ee45e94
3 changed files with 68 additions and 58 deletions
|
@ -22,6 +22,8 @@ class CollectionBuilder:
|
|||
self.posters = []
|
||||
self.backgrounds = []
|
||||
self.schedule = None
|
||||
current_time = datetime.now()
|
||||
current_year = current_time.year
|
||||
|
||||
if "template" in data:
|
||||
if not self.library.templates:
|
||||
|
@ -113,7 +115,6 @@ class CollectionBuilder:
|
|||
skip_collection = False
|
||||
else:
|
||||
schedule_list = util.get_list(data["schedule"])
|
||||
current_time = datetime.now()
|
||||
next_month = current_time.replace(day=28) + timedelta(days=4)
|
||||
last_day = next_month - timedelta(days=next_month.day)
|
||||
for schedule in schedule_list:
|
||||
|
@ -316,10 +317,24 @@ class CollectionBuilder:
|
|||
logger.warning(f"Collection Warning: {f} filter will run as {filter_method}")
|
||||
else:
|
||||
filter_method = f
|
||||
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")
|
||||
elif data[m][f] is None: raise Failed(f"Collection Error: {filter_method} filter is blank")
|
||||
elif filter_method in util.all_filters: self.filters.append((filter_method, data[m][f]))
|
||||
else: raise Failed(f"Collection Error: {filter_method} filter not supported")
|
||||
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")
|
||||
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)))
|
||||
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)))
|
||||
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)))
|
||||
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")))
|
||||
elif filter_method in util.all_filters:
|
||||
self.filters.append((filter_method, data[m][f]))
|
||||
else:
|
||||
raise Failed(f"Collection Error: {filter_method} filter not supported")
|
||||
elif method_name == "plex_collectionless":
|
||||
new_dictionary = {}
|
||||
prefix_list = []
|
||||
|
@ -396,24 +411,11 @@ class CollectionBuilder:
|
|||
if attr_data is True:
|
||||
new_dictionary[attr] = attr_data
|
||||
elif attr in ["primary_release_date.gte", "primary_release_date.lte", "release_date.gte", "release_date.lte", "air_date.gte", "air_date.lte", "first_air_date.gte", "first_air_date.lte"]:
|
||||
if re.compile("[0-1]?[0-9][/-][0-3]?[0-9][/-][1-2][890][0-9][0-9]").match(str(attr_data)):
|
||||
the_date = str(attr_data).split("/") if "/" in str(attr_data) else str(attr_data).split("-")
|
||||
new_dictionary[attr] = f"{the_date[2]}-{the_date[0]}-{the_date[1]}"
|
||||
elif re.compile("[1-2][890][0-9][0-9][/-][0-1]?[0-9][/-][0-3]?[0-9]").match(str(attr_data)):
|
||||
the_date = str(attr_data).split("/") if "/" in str(attr_data) else str(attr_data).split("-")
|
||||
new_dictionary[attr] = f"{the_date[0]}-{the_date[1]}-{the_date[2]}"
|
||||
else:
|
||||
raise Failed(f"Collection Error: {m} attribute {attr}: {attr_data} must match pattern MM/DD/YYYY e.g. 12/25/2020")
|
||||
new_dictionary[attr] = util.check_date(attr_data, f"{m} attribute {attr}", return_string=True)
|
||||
elif attr in ["primary_release_year", "year", "first_air_date_year"]:
|
||||
if isinstance(attr_data, int) and 1800 < attr_data < 2200:
|
||||
new_dictionary[attr] = attr_data
|
||||
else:
|
||||
raise Failed(f"Collection Error: {m} attribute {attr}: must be a valid year e.g. 1990")
|
||||
new_dictionary[attr] = util.check_number(attr_data, f"{m} attribute {attr}", minimum=1800, maximum=current_year + 1)
|
||||
elif attr in ["vote_count.gte", "vote_count.lte", "vote_average.gte", "vote_average.lte", "with_runtime.gte", "with_runtime.lte"]:
|
||||
if (isinstance(attr_data, int) or isinstance(attr_data, float)) and 0 < attr_data:
|
||||
new_dictionary[attr] = attr_data
|
||||
else:
|
||||
raise Failed(f"Collection Error: {m} attribute {attr}: must be a valid number greater then 0")
|
||||
new_dictionary[attr] = util.check_number(attr_data, f"{m} attribute {attr}", minimum=1)
|
||||
elif attr 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[attr] = attr_data
|
||||
else:
|
||||
|
@ -448,7 +450,6 @@ class CollectionBuilder:
|
|||
elif data[m]["sort_by"] not in util.mal_season_sort: logger.warning(f"Collection Warning: mal_season sort_by attribute {data[m]['sort_by']} invalid must be either 'members' or 'score' using members as default")
|
||||
else: new_dictionary["sort_by"] = util.mal_season_sort[data[m]["sort_by"]]
|
||||
|
||||
current_time = datetime.now()
|
||||
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 [7, 8, 9]: new_dictionary["season"] = "summer"
|
||||
|
|
|
@ -139,8 +139,7 @@ class PlexAPI:
|
|||
method = util.filter_alias[f[0][:-4]] if modifier in [".not", ".lte", ".gte"] else util.filter_alias[f[0]]
|
||||
if method == "max_age":
|
||||
threshold_date = datetime.now() - timedelta(days=f[1])
|
||||
attr = getattr(current, "originallyAvailableAt")
|
||||
if attr is None or attr < threshold_date:
|
||||
if current.originallyAvailableAt is None or current.originallyAvailableAt < threshold_date:
|
||||
match = False
|
||||
break
|
||||
elif method == "original_language":
|
||||
|
@ -160,17 +159,12 @@ class PlexAPI:
|
|||
match = False
|
||||
break
|
||||
elif modifier in [".gte", ".lte"]:
|
||||
if method == "originallyAvailableAt":
|
||||
threshold_date = datetime.strptime(f[1], "%m/%d/%y")
|
||||
attr = getattr(current, "originallyAvailableAt")
|
||||
if (modifier == ".lte" and attr > threshold_date) or (modifier == ".gte" and attr < threshold_date):
|
||||
match = False
|
||||
break
|
||||
elif method in ["year", "rating"]:
|
||||
attr = getattr(current, method)
|
||||
if (modifier == ".lte" and attr > f[1]) or (modifier == ".gte" and attr < f[1]):
|
||||
match = False
|
||||
break
|
||||
attr = getattr(current, method)
|
||||
if method == "duration":
|
||||
attr = attr / 60000
|
||||
if (modifier == ".lte" and attr > f[1]) or (modifier == ".gte" and attr < f[1]):
|
||||
match = False
|
||||
break
|
||||
else:
|
||||
terms = util.get_list(f[1])
|
||||
attrs = []
|
||||
|
@ -214,11 +208,7 @@ class PlexAPI:
|
|||
logger.info("")
|
||||
year = None
|
||||
if "year" in self.metadata[m]:
|
||||
now = datetime.now()
|
||||
if self.metadata[m]["year"] is None: logger.error("Metadata Error: year attribute is blank")
|
||||
elif not isinstance(self.metadata[m]["year"], int): logger.error("Metadata Error: year attribute must be an integer")
|
||||
elif self.metadata[m]["year"] not in range(1800, now.year + 2): logger.error(f"Metadata Error: year attribute must be between 1800-{now.year + 1}")
|
||||
else: year = self.metadata[m]["year"]
|
||||
year = util.check_number(self.metadata[m]["year"], "year", minimum=1800, maximum=datetime.now().year + 1)
|
||||
|
||||
title = m
|
||||
if "title" in self.metadata[m]:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import datetime, logging, re, signal, sys, time, traceback
|
||||
import logging, re, signal, sys, time, traceback
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import msvcrt
|
||||
|
@ -369,6 +370,7 @@ all_filters = [
|
|||
"genre", "genre.not",
|
||||
"max_age",
|
||||
"originally_available.gte", "originally_available.lte",
|
||||
"duration.gte", "duration.lte",
|
||||
"original_language", "original_language.not",
|
||||
"rating.gte", "rating.lte",
|
||||
"studio", "studio.not",
|
||||
|
@ -381,6 +383,7 @@ movie_only_filters = [
|
|||
"audio_language", "audio_language.not",
|
||||
"country", "country.not",
|
||||
"director", "director.not",
|
||||
"duration.gte", "duration.lte",
|
||||
"original_language", "original_language.not",
|
||||
"subtitle_language", "subtitle_language.not",
|
||||
"video_resolution", "video_resolution.not",
|
||||
|
@ -511,33 +514,49 @@ def get_int_list(data, id_type):
|
|||
def get_year_list(data, method):
|
||||
values = get_list(data)
|
||||
final_years = []
|
||||
current_year = datetime.datetime.now().year
|
||||
current_year = datetime.now().year
|
||||
for value in values:
|
||||
try:
|
||||
if "-" in value:
|
||||
year_range = re.search("(\\d{4})-(\\d{4}|NOW)", str(value))
|
||||
start = year_range.group(1)
|
||||
end = year_range.group(2)
|
||||
if end == "NOW":
|
||||
end = current_year
|
||||
if int(start) < 1800 or int(start) > current_year: logger.error(f"Collection Error: Skipping {method} starting year {start} must be between 1800 and {current_year}")
|
||||
elif int(end) < 1800 or int(end) > current_year: logger.error(f"Collection Error: Skipping {method} ending year {end} must be between 1800 and {current_year}")
|
||||
elif int(start) > int(end): logger.error(f"Collection Error: Skipping {method} starting year {start} cannot be greater then ending year {end}")
|
||||
start = check_year(year_range.group(1), current_year, method)
|
||||
end = current_year if year_range.group(2) == "NOW" else check_year(year_range.group(2), current_year, method)
|
||||
if int(start) > int(end):
|
||||
raise Failed(f"Collection Error: {method} starting year: {start} cannot be greater then ending year {end}")
|
||||
else:
|
||||
for i in range(int(start), int(end) + 1):
|
||||
final_years.append(i)
|
||||
final_years.append(int(i))
|
||||
else:
|
||||
year = re.search("(\\d+)", str(value)).group(1)
|
||||
if int(year) < 1800 or int(year) > current_year:
|
||||
logger.error(f"Collection Error: Skipping {method} year {year} must be between 1800 and {current_year}")
|
||||
else:
|
||||
if len(str(year)) != len(str(value)):
|
||||
logger.warning(f"Collection Warning: {value} can be replaced with {year}")
|
||||
final_years.append(year)
|
||||
final_years.append(check_year(value, current_year, method))
|
||||
except AttributeError:
|
||||
logger.error(f"Collection Error: Skipping {method} failed to parse year from {value}")
|
||||
raise Failed(f"Collection Error: {method} failed to parse year from {value}")
|
||||
return final_years
|
||||
|
||||
def check_year(year, current_year, method):
|
||||
return check_number(year, method, minimum=1800, maximum=current_year)
|
||||
|
||||
def check_number(value, method, number_type="int", minimum=None, maximum=None):
|
||||
if number_type == "int":
|
||||
try: num_value = int(str(value))
|
||||
except ValueError: raise Failed(f"Collection Error: {method}: {value} must be an integer")
|
||||
elif number_type == "float":
|
||||
try: num_value = float(str(value))
|
||||
except ValueError: raise Failed(f"Collection Error: {method}: {value} must be a number")
|
||||
else: raise Failed(f"Number Type: {number_type} invalid")
|
||||
if minimum is not None and maximum is not None and (num_value < minimum or num_value > maximum):
|
||||
raise Failed(f"Collection Error: {method}: {num_value} must be between {minimum} and {maximum}")
|
||||
elif minimum is not None and num_value < minimum:
|
||||
raise Failed(f"Collection Error: {method}: {num_value} is less then {minimum}")
|
||||
elif maximum is not None and num_value > maximum:
|
||||
raise Failed(f"Collection Error: {method}: {num_value} is greater then {maximum}")
|
||||
else:
|
||||
return num_value
|
||||
|
||||
def check_date(date_text, method, return_string=False):
|
||||
try: date_obg = datetime.strptime(str(date_text), "%m/%d/%Y")
|
||||
except ValueError: raise Failed(f"Collection Error: {method}: {date_text} must match pattern MM/DD/YYYY e.g. 12/25/2020")
|
||||
return str(date_text) if return_string else date_obg
|
||||
|
||||
def logger_input(prompt, timeout=60):
|
||||
if windows: return windows_input(prompt, timeout)
|
||||
elif hasattr(signal, "SIGALRM"): return unix_input(prompt, timeout)
|
||||
|
|
Loading…
Reference in a new issue