mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-22 04:23:08 +00:00
Add schedule to library
This commit is contained in:
parent
203ee10ca9
commit
37c719e505
5 changed files with 127 additions and 97 deletions
|
@ -369,91 +369,9 @@ class CollectionBuilder:
|
|||
raise Failed(f"{self.Type} Error: schedule attribute is blank")
|
||||
else:
|
||||
logger.debug(f"Value: {self.data[methods['schedule']]}")
|
||||
skip_collection = True
|
||||
schedule_list = util.get_list(self.data[methods["schedule"]])
|
||||
next_month = self.current_time.replace(day=28) + timedelta(days=4)
|
||||
last_day = next_month - timedelta(days=next_month.day)
|
||||
for schedule in schedule_list:
|
||||
run_time = str(schedule).lower()
|
||||
if run_time.startswith(("day", "daily")):
|
||||
skip_collection = False
|
||||
elif run_time == "never":
|
||||
self.schedule += f"\nNever scheduled to run"
|
||||
elif run_time.startswith(("hour", "week", "month", "year", "range")):
|
||||
match = re.search("\\(([^)]+)\\)", run_time)
|
||||
if not match:
|
||||
logger.error(f"{self.Type} Error: failed to parse schedule: {schedule}")
|
||||
continue
|
||||
param = match.group(1)
|
||||
if run_time.startswith("hour"):
|
||||
try:
|
||||
if 0 <= int(param) <= 23:
|
||||
self.schedule += f"\nScheduled to run only on the {util.make_ordinal(int(param))} hour"
|
||||
if self.config.run_hour == int(param):
|
||||
skip_collection = False
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.error(f"{self.Type} Error: hourly schedule attribute {schedule} invalid must be an integer between 0 and 23")
|
||||
elif run_time.startswith("week"):
|
||||
if param.lower() not in util.days_alias:
|
||||
logger.error(f"{self.Type} Error: weekly schedule attribute {schedule} invalid must be a day of the week i.e. weekly(Monday)")
|
||||
continue
|
||||
weekday = util.days_alias[param.lower()]
|
||||
self.schedule += f"\nScheduled weekly on {util.pretty_days[weekday]}"
|
||||
if weekday == self.current_time.weekday():
|
||||
skip_collection = False
|
||||
elif run_time.startswith("month"):
|
||||
try:
|
||||
if 1 <= int(param) <= 31:
|
||||
self.schedule += f"\nScheduled monthly on the {util.make_ordinal(int(param))}"
|
||||
if self.current_time.day == int(param) or (self.current_time.day == last_day.day and int(param) > last_day.day):
|
||||
skip_collection = False
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.error(f"{self.Type} Error: monthly schedule attribute {schedule} invalid must be an integer between 1 and 31")
|
||||
elif run_time.startswith("year"):
|
||||
try:
|
||||
if "/" in param:
|
||||
opt = param.split("/")
|
||||
month = int(opt[0])
|
||||
day = int(opt[1])
|
||||
self.schedule += f"\nScheduled yearly on {util.pretty_months[month]} {util.make_ordinal(day)}"
|
||||
if self.current_time.month == month and (self.current_time.day == day or (self.current_time.day == last_day.day and day > last_day.day)):
|
||||
skip_collection = False
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.error(f"{self.Type} Error: yearly schedule attribute {schedule} invalid must be in the MM/DD format i.e. yearly(11/22)")
|
||||
elif run_time.startswith("range"):
|
||||
match = re.match("^(1[0-2]|0?[1-9])/(3[01]|[12][0-9]|0?[1-9])-(1[0-2]|0?[1-9])/(3[01]|[12][0-9]|0?[1-9])$", param)
|
||||
if not match:
|
||||
logger.error(f"{self.Type} Error: range schedule attribute {schedule} invalid must be in the MM/DD-MM/DD format i.e. range(12/01-12/25)")
|
||||
continue
|
||||
def check_day(_m, _d):
|
||||
if _m in [1, 3, 5, 7, 8, 10, 12] and _d > 31:
|
||||
return _m, 31
|
||||
elif _m in [4, 6, 9, 11] and _d > 30:
|
||||
return _m, 30
|
||||
elif _m == 2 and _d > 28:
|
||||
return _m, 28
|
||||
else:
|
||||
return _m, _d
|
||||
month_start, day_start = check_day(int(match.group(1)), int(match.group(2)))
|
||||
month_end, day_end = check_day(int(match.group(3)), int(match.group(4)))
|
||||
month_check, day_check = check_day(self.current_time.month, self.current_time.day)
|
||||
check = datetime.strptime(f"{month_check}/{day_check}", "%m/%d")
|
||||
start = datetime.strptime(f"{month_start}/{day_start}", "%m/%d")
|
||||
end = datetime.strptime(f"{month_end}/{day_end}", "%m/%d")
|
||||
self.schedule += f"\nScheduled between {util.pretty_months[month_start]} {util.make_ordinal(day_start)} and {util.pretty_months[month_end]} {util.make_ordinal(day_end)}"
|
||||
if start <= check <= end if start < end else check <= end or check >= start:
|
||||
skip_collection = False
|
||||
else:
|
||||
logger.error(f"{self.Type} Error: schedule attribute {schedule} invalid")
|
||||
if len(self.schedule) == 0:
|
||||
skip_collection = False
|
||||
if skip_collection:
|
||||
try:
|
||||
util.schedule_check(self.data[methods['schedule']], self.current_time, self.config.run_hour)
|
||||
except NotScheduled as e:
|
||||
suffix = ""
|
||||
if self.details["delete_not_scheduled"]:
|
||||
try:
|
||||
|
@ -463,7 +381,7 @@ class CollectionBuilder:
|
|||
suffix = f" and was deleted"
|
||||
except Failed:
|
||||
suffix = f" and could not be found to delete"
|
||||
raise NotScheduled(f"{self.schedule}\n\nCollection {self.name} not scheduled to run{suffix}")
|
||||
raise NotScheduled(f"{e}\n\nCollection {self.name} not scheduled to run{suffix}")
|
||||
|
||||
self.collectionless = "plex_collectionless" in methods and not self.playlist
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ from modules.tautulli import Tautulli
|
|||
from modules.tmdb import TMDb
|
||||
from modules.trakt import Trakt
|
||||
from modules.tvdb import TVDb
|
||||
from modules.util import Failed
|
||||
from modules.util import Failed, NotScheduled
|
||||
from modules.webhooks import Webhooks
|
||||
from retrying import retry
|
||||
from ruamel import yaml
|
||||
|
@ -473,6 +473,8 @@ class ConfigFile:
|
|||
self.libraries = []
|
||||
libs = check_for_attribute(self.data, "libraries", throw=True)
|
||||
|
||||
current_time = datetime.now()
|
||||
|
||||
for library_name, lib in libs.items():
|
||||
if self.requested_libraries and library_name not in self.requested_libraries:
|
||||
continue
|
||||
|
@ -611,6 +613,18 @@ class ConfigFile:
|
|||
else:
|
||||
params["metadata_path"] = [("File", os.path.join(default_dir, f"{library_name}.yml"))]
|
||||
params["default_dir"] = default_dir
|
||||
|
||||
params["skip_library"] = False
|
||||
if lib and "schedule" in lib:
|
||||
if not lib["schedule"]:
|
||||
raise Failed(f"Config Error: schedule attribute is blank")
|
||||
else:
|
||||
logger.debug(f"Value: {lib['schedule']}")
|
||||
try:
|
||||
util.schedule_check(lib["schedule"], current_time, self.run_hour)
|
||||
except NotScheduled:
|
||||
params["skip_library"] = True
|
||||
|
||||
params["plex"] = {
|
||||
"url": check_for_attribute(lib, "url", parent="plex", var_type="url", default=self.general["plex"]["url"], req_default=True, save=False),
|
||||
"token": check_for_attribute(lib, "token", parent="plex", default=self.general["plex"]["token"], req_default=True, save=False),
|
||||
|
|
|
@ -34,6 +34,7 @@ class Library(ABC):
|
|||
self.name = params["name"]
|
||||
self.original_mapping_name = params["mapping_name"]
|
||||
self.metadata_path = params["metadata_path"]
|
||||
self.skip_library = params["skip_library"]
|
||||
self.asset_depth = params["asset_depth"]
|
||||
self.asset_directory = params["asset_directory"] if params["asset_directory"] else []
|
||||
self.default_dir = params["default_dir"]
|
||||
|
|
113
modules/util.py
113
modules/util.py
|
@ -277,26 +277,26 @@ def is_locked(filepath):
|
|||
file_object.close()
|
||||
return locked
|
||||
|
||||
def time_window(time_window):
|
||||
def time_window(tw):
|
||||
today = datetime.now()
|
||||
if time_window == "today":
|
||||
if tw == "today":
|
||||
return f"{today:%Y-%m-%d}"
|
||||
elif time_window == "yesterday":
|
||||
elif tw == "yesterday":
|
||||
return f"{today - timedelta(days=1):%Y-%m-%d}"
|
||||
elif time_window == "this_week":
|
||||
elif tw == "this_week":
|
||||
return f"{today:%Y-0%V}"
|
||||
elif time_window == "last_week":
|
||||
elif tw == "last_week":
|
||||
return f"{today - timedelta(weeks=1):%Y-0%V}"
|
||||
elif time_window == "this_month":
|
||||
elif tw == "this_month":
|
||||
return f"{today:%Y-%m}"
|
||||
elif time_window == "last_month":
|
||||
elif tw == "last_month":
|
||||
return f"{today.year}-{today.month - 1 or 12}"
|
||||
elif time_window == "this_year":
|
||||
elif tw == "this_year":
|
||||
return f"{today.year}"
|
||||
elif time_window == "last_year":
|
||||
elif tw == "last_year":
|
||||
return f"{today.year - 1}"
|
||||
else:
|
||||
return time_window
|
||||
return tw
|
||||
|
||||
def glob_filter(filter_in):
|
||||
filter_in = filter_in.translate({ord("["): "[[]", ord("]"): "[]]"}) if "[" in filter_in else filter_in
|
||||
|
@ -347,3 +347,96 @@ def is_string_filter(values, modifier, data):
|
|||
if jailbreak: break
|
||||
return (jailbreak and modifier in [".not", ".isnot"]) or (not jailbreak and modifier in ["", ".is", ".begins", ".ends", ".regex"])
|
||||
|
||||
def schedule_check(data, current_time, run_hour):
|
||||
skip_collection = True
|
||||
schedule_list = get_list(data)
|
||||
next_month = current_time.replace(day=28) + timedelta(days=4)
|
||||
last_day = next_month - timedelta(days=next_month.day)
|
||||
schedule_str = ""
|
||||
for schedule in schedule_list:
|
||||
run_time = str(schedule).lower()
|
||||
if run_time.startswith(("day", "daily")):
|
||||
skip_collection = False
|
||||
elif run_time == "never":
|
||||
schedule_str += f"\nNever scheduled to run"
|
||||
elif run_time.startswith(("hour", "week", "month", "year", "range")):
|
||||
match = re.search("\\(([^)]+)\\)", run_time)
|
||||
if not match:
|
||||
logger.error(f"Schedule Error: failed to parse schedule: {schedule}")
|
||||
continue
|
||||
param = match.group(1)
|
||||
if run_time.startswith("hour"):
|
||||
try:
|
||||
if 0 <= int(param) <= 23:
|
||||
schedule_str += f"\nScheduled to run only on the {make_ordinal(int(param))} hour"
|
||||
if run_hour == int(param):
|
||||
skip_collection = False
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.error(f"Schedule Error: hourly schedule attribute {schedule} invalid must be an integer between 0 and 23")
|
||||
elif run_time.startswith("week"):
|
||||
if param.lower() not in days_alias:
|
||||
logger.error(f"Schedule Error: weekly schedule attribute {schedule} invalid must be a day of the week i.e. weekly(Monday)")
|
||||
continue
|
||||
weekday = days_alias[param.lower()]
|
||||
schedule_str += f"\nScheduled weekly on {pretty_days[weekday]}"
|
||||
if weekday == current_time.weekday():
|
||||
skip_collection = False
|
||||
elif run_time.startswith("month"):
|
||||
try:
|
||||
if 1 <= int(param) <= 31:
|
||||
schedule_str += f"\nScheduled monthly on the {make_ordinal(int(param))}"
|
||||
if current_time.day == int(param) or (
|
||||
current_time.day == last_day.day and int(param) > last_day.day):
|
||||
skip_collection = False
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.error(f"Schedule Error: monthly schedule attribute {schedule} invalid must be an integer between 1 and 31")
|
||||
elif run_time.startswith("year"):
|
||||
try:
|
||||
if "/" in param:
|
||||
opt = param.split("/")
|
||||
month = int(opt[0])
|
||||
day = int(opt[1])
|
||||
schedule_str += f"\nScheduled yearly on {pretty_months[month]} {make_ordinal(day)}"
|
||||
if current_time.month == month and (current_time.day == day or (
|
||||
current_time.day == last_day.day and day > last_day.day)):
|
||||
skip_collection = False
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.error(
|
||||
f"Schedule Error: yearly schedule attribute {schedule} invalid must be in the MM/DD format i.e. yearly(11/22)")
|
||||
elif run_time.startswith("range"):
|
||||
match = re.match("^(1[0-2]|0?[1-9])/(3[01]|[12][0-9]|0?[1-9])-(1[0-2]|0?[1-9])/(3[01]|[12][0-9]|0?[1-9])$", param)
|
||||
if not match:
|
||||
logger.error(f"Schedule Error: range schedule attribute {schedule} invalid must be in the MM/DD-MM/DD format i.e. range(12/01-12/25)")
|
||||
continue
|
||||
|
||||
def check_day(_m, _d):
|
||||
if _m in [1, 3, 5, 7, 8, 10, 12] and _d > 31:
|
||||
return _m, 31
|
||||
elif _m in [4, 6, 9, 11] and _d > 30:
|
||||
return _m, 30
|
||||
elif _m == 2 and _d > 28:
|
||||
return _m, 28
|
||||
else:
|
||||
return _m, _d
|
||||
|
||||
month_start, day_start = check_day(int(match.group(1)), int(match.group(2)))
|
||||
month_end, day_end = check_day(int(match.group(3)), int(match.group(4)))
|
||||
month_check, day_check = check_day(current_time.month, current_time.day)
|
||||
check = datetime.strptime(f"{month_check}/{day_check}", "%m/%d")
|
||||
start = datetime.strptime(f"{month_start}/{day_start}", "%m/%d")
|
||||
end = datetime.strptime(f"{month_end}/{day_end}", "%m/%d")
|
||||
schedule_str += f"\nScheduled between {pretty_months[month_start]} {make_ordinal(day_start)} and {pretty_months[month_end]} {make_ordinal(day_end)}"
|
||||
if start <= check <= end if start < end else check <= end or check >= start:
|
||||
skip_collection = False
|
||||
else:
|
||||
logger.error(f"Schedule Error: schedule attribute {schedule} invalid")
|
||||
if len(schedule_str) == 0:
|
||||
skip_collection = False
|
||||
if skip_collection:
|
||||
raise NotScheduled(schedule_str)
|
||||
|
|
|
@ -189,6 +189,10 @@ def start(attrs):
|
|||
def update_libraries(config):
|
||||
global stats
|
||||
for library in config.libraries:
|
||||
if library.skip_library:
|
||||
logger.info("")
|
||||
util.separator(f"Skipping {library.name} Library")
|
||||
continue
|
||||
try:
|
||||
os.makedirs(os.path.join(default_dir, "logs", library.mapping_name, "collections"), exist_ok=True)
|
||||
col_file_logger = os.path.join(default_dir, "logs", library.mapping_name, "library.log")
|
||||
|
|
Loading…
Reference in a new issue