From 0328b359ac44ef92b9617d5bc30f61dd208a779d Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Fri, 24 Feb 2023 10:52:23 -0500 Subject: [PATCH] [92] add metadata image sets --- VERSION | 2 +- modules/config.py | 1 + modules/meta.py | 106 +++++++++++++++++++++++++++++++++------------- modules/plex.py | 6 ++- modules/util.py | 23 ++++++---- 5 files changed, 97 insertions(+), 41 deletions(-) diff --git a/VERSION b/VERSION index 5bdafed4..23f7d402 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.18.3-develop91 +1.18.3-develop92 diff --git a/modules/config.py b/modules/config.py index f699b5f6..a8bccf42 100644 --- a/modules/config.py +++ b/modules/config.py @@ -398,6 +398,7 @@ class ConfigFile: "check_nightly": check_for_attribute(self.data, "check_nightly", parent="settings", var_type="bool", default=False), "assets_for_all": check_for_attribute(self.data, "assets_for_all", parent="settings", var_type="bool", default=False, save=False, do_print=False) } + self.image_sets = {} self.custom_repo = None if self.general["custom_repo"]: repo = self.general["custom_repo"] diff --git a/modules/meta.py b/modules/meta.py index d0c2e512..758e4477 100644 --- a/modules/meta.py +++ b/modules/meta.py @@ -126,18 +126,16 @@ class DataFile: defaults_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "defaults") if overlay: defaults_path = os.path.join(defaults_path, "overlays") - if os.path.exists(os.path.abspath(os.path.join(defaults_path, file_path))): - file_path = os.path.abspath(os.path.join(defaults_path, file_path)) + if os.path.exists(os.path.join(defaults_path, file_path)): + file_path = os.path.join(defaults_path, file_path) elif self.library: for default_folder in [self.library.type.lower(), "both", "chart", "award"]: - if os.path.exists(os.path.abspath(os.path.join(defaults_path, default_folder, file_path))): - file_path = os.path.abspath(os.path.join(defaults_path, default_folder, file_path)) + if os.path.exists(os.path.join(defaults_path, default_folder, file_path)): + file_path = os.path.join(defaults_path, default_folder, file_path) break content_path = os.path.abspath(os.path.join(file_path, "default.yml") if translation else file_path) dir_path = file_path if not os.path.exists(content_path): - if os.path.exists(os.path.join("config", content_path)): - content_path = os.path.join("config", content_path) if file_type == "PMM Default": raise Failed(f"File Error: Default does not exist {file_path}") else: @@ -1436,7 +1434,45 @@ class MetadataFile(DataFile): else: logger.error(f"{mapping_name} Advanced Details Update Failed") - asset_location, folder_name, ups = self.library.item_images(item, meta, methods, initial=True, asset_directory=self.asset_directory + self.library.asset_directory if self.asset_directory else None) + image_set_data = None + if "image_set" in methods: + logger.debug("") + logger.debug("Validating Method: image_set") + set_files = meta[methods["image_set"]] + if not set_files: + raise Failed("Metadata Error: image_set attribute is blank") + logger.debug(f"Value: {set_files}") + set_dict = set_files[0] if isinstance(set_files, list) else set_files + if not isinstance(set_dict, dict): + raise Failed("Metadata Error: No image_set path dictionary found") + elif not set_dict: + raise Failed("Metadata Error: image_set path dictionary is empty") + set_name = "" + for k, v in set_dict.items(): + set_name = f"{k}: {v}" + break + if set_name not in self.config.image_sets: + files = util.load_files(meta[methods["image_set"]], "image_set", err_type="Metadata", single=True) + if not files: + raise Failed("Metadata Error: No Path Found for image_set") + file_type, set_file, _, _ = files[0] + temp_data = self.load_file(file_type, set_file) + if "set" not in temp_data: + raise Failed('Image Set Error: Image sets must use the base attribute "set"') + if not isinstance(temp_data, dict): + raise Failed("Image Set Error: Image set must be a dictionary") + if not temp_data["set"]: + raise Failed("Image Set Error: Image set attribute is empty") + if not isinstance(temp_data["set"], dict): + raise Failed("Image Set Error: Image set set attribute must be a dictionary") + self.config.image_sets[set_name] = temp_data["set"] + image_set_data = self.config.image_sets[set_name] + + main_set_data = None + if image_set_data and mapping_name in image_set_data: + main_set_data = image_set_data[mapping_name] + + asset_location, folder_name, ups = self.library.item_images(item, meta, methods, initial=True, asset_directory=self.asset_directory + self.library.asset_directory if self.asset_directory else None, image_set=main_set_data) if ups: updated = True logger.info(f"{self.library.type}: {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}") @@ -1445,27 +1481,29 @@ class MetadataFile(DataFile): if "update_seasons" in methods and self.library.is_show: logger.debug("") logger.debug("Validating Method: update_seasons") - if meta[methods["update_seasons"]] is None: + if not meta[methods["update_seasons"]]: logger.warning("Metadata Warning: update_seasons has no value and season updates will be performed") - logger.debug(f"Value: {meta[methods['update_seasons']]}") - for library_type in util.get_list(meta[methods["run_definition"]], lower=True): - if library_type not in ["true", "false"]: - raise Failed(f"Metadata Error: {library_type} is invalid. Options: true or false") - elif library_type == "false": - update_seasons = False + else: + logger.debug(f"Value: {meta[methods['update_seasons']]}") + for library_type in util.get_list(meta[methods["run_definition"]], lower=True): + if library_type not in ["true", "false"]: + raise Failed(f"Metadata Error: {library_type} is invalid. Options: true or false") + elif library_type == "false": + update_seasons = False update_episodes = True if "update_episodes" in methods and self.library.is_show: logger.debug("") logger.debug("Validating Method: update_episodes") - if meta[methods["update_episodes"]] is None: + if not meta[methods["update_episodes"]]: logger.warning("Metadata Warning: update_episodes has no value and episode updates will be performed") - logger.debug(f"Value: {meta[methods['update_episodes']]}") - for library_type in util.get_list(meta[methods["run_definition"]], lower=True): - if library_type not in ["true", "false"]: - raise Failed(f"Metadata Error: {library_type} is invalid. Options: true or false") - elif library_type == "false": - update_episodes = False + else: + logger.debug(f"Value: {meta[methods['update_episodes']]}") + for library_type in util.get_list(meta[methods["run_definition"]], lower=True): + if library_type not in ["true", "false"]: + raise Failed(f"Metadata Error: {library_type} is invalid. Options: true or false") + elif library_type == "false": + update_episodes = False if "seasons" in methods and self.library.is_show and (update_seasons or update_episodes): if not meta[methods["seasons"]]: @@ -1487,6 +1525,7 @@ class MetadataFile(DataFile): logger.error(f"Metadata Error: Season: {season_id} not found") continue season_methods = {sm.lower(): sm for sm in season_dict} + season_image_set = None if update_seasons: #season.batchEdits() add_edit("title", season, season_dict, season_methods) @@ -1495,9 +1534,12 @@ class MetadataFile(DataFile): if self.edit_tags("label", season, season_dict, season_methods): updated = True finish_edit(season, f"Season: {season_id}") + if main_set_data and "seasons" in main_set_data and main_set_data["seasons"] and season_id in main_set_data["seasons"]: + season_image_set = main_set_data["seasons"][season_id] _, _, ups = self.library.item_images(season, season_dict, season_methods, asset_location=asset_location, title=f"{item.title} Season {season.seasonNumber}", - image_name=f"Season{'0' if season.seasonNumber < 10 else ''}{season.seasonNumber}", folder_name=folder_name) + image_name=f"Season{'0' if season.seasonNumber < 10 else ''}{season.seasonNumber}", + folder_name=folder_name, image_set=season_image_set) if ups: updated = True logger.info(f"Season {season_id} of {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}") @@ -1512,14 +1554,14 @@ class MetadataFile(DataFile): for episode in season.episodes(): episodes[episode.title] = episode episodes[int(episode.index)] = episode - for episode_str, episode_dict in season_dict[season_methods["episodes"]].items(): + for episode_id, episode_dict in season_dict[season_methods["episodes"]].items(): updated = False logger.info("") - logger.info(f"Updating episode {episode_str} in {season_id} of {mapping_name}...") - if episode_str in episodes: - episode = episodes[episode_str] + logger.info(f"Updating episode {episode_id} in {season_id} of {mapping_name}...") + if episode_id in episodes: + episode = episodes[episode_id] else: - logger.error(f"Metadata Error: Episode {episode_str} in Season {season_id} not found") + logger.error(f"Metadata Error: Episode {episode_id} in Season {season_id} not found") continue episode_methods = {em.lower(): em for em in episode_dict} #episode.batchEdits() @@ -1534,13 +1576,17 @@ class MetadataFile(DataFile): for tag_edit in ["director", "writer", "label"]: if self.edit_tags(tag_edit, episode, episode_dict, episode_methods): updated = True - finish_edit(episode, f"Episode: {episode_str} in Season: {season_id}") + finish_edit(episode, f"Episode: {episode_id} in Season: {season_id}") + episode_image_set = None + if season_image_set and "episodes" in season_image_set and season_image_set["episodes"] and episode_id in season_image_set["episodes"]: + episode_image_set = season_image_set["episodes"][episode_id] _, _, ups = self.library.item_images(episode, episode_dict, episode_methods, asset_location=asset_location, title=f"{item.title} {episode.seasonEpisode.upper()}", - image_name=episode.seasonEpisode.upper(), folder_name=folder_name) + image_name=episode.seasonEpisode.upper(), folder_name=folder_name, + image_set=episode_image_set) if ups: updated = True - logger.info(f"Episode {episode_str} in Season {season_id} of {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}") + logger.info(f"Episode {episode_id} in Season {season_id} of {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}") if "episodes" in methods and update_episodes and self.library.is_show: if not meta[methods["episodes"]]: diff --git a/modules/plex.py b/modules/plex.py index 14a5f6e5..935623fe 100644 --- a/modules/plex.py +++ b/modules/plex.py @@ -1168,10 +1168,14 @@ class Plex(Library): else: logger.warning(f"{text} | No Reset Image Found") - def item_images(self, item, group, alias, initial=False, asset_location=None, asset_directory=None, title=None, image_name=None, folder_name=None): + def item_images(self, item, group, alias, initial=False, asset_location=None, asset_directory=None, title=None, image_name=None, folder_name=None, image_set=None): if title is None: title = item.title posters, backgrounds = util.get_image_dicts(group, alias) + if image_set and "poster" in image_set: + posters["image_set"] = image_set["poster"] + if image_set and "background" in image_set: + backgrounds["image_set"] = image_set["background"] try: asset_poster, asset_background, item_dir, folder_name = self.find_item_assets(item, item_asset_directory=asset_location, asset_directory=asset_directory) if asset_poster: diff --git a/modules/util.py b/modules/util.py index 4518fa78..80deb106 100644 --- a/modules/util.py +++ b/modules/util.py @@ -199,6 +199,8 @@ def pick_image(title, images, prioritize_assets, download_url_assets, item_dir, final_attr = None if prioritize_assets and "asset_directory" in images: return images["asset_directory"] + elif "image_set" in images: + final_attr = "image_set" elif f"url_{image_type}" in images: if download_url_assets and item_dir: if "asset_directory" in images: @@ -432,11 +434,14 @@ def time_window(tw): else: return tw -def load_files(files_to_load, method, schedule=None, lib_vars=None): +def load_files(files_to_load, method, err_type="Config", schedule=None, lib_vars=None, single=False): files = [] if not lib_vars: lib_vars = {} - for file in get_list(files_to_load, split=False): + files_to_load = get_list(files_to_load, split=False) + if single and len(files_to_load) > 1: + raise Failed(f"{err_type} Error: {method} can only have one entry") + for file in files_to_load: if isinstance(file, dict): temp_vars = {} if "template_variables" in file and file["template_variables"] and isinstance(file["template_variables"], dict): @@ -450,7 +455,7 @@ def load_files(files_to_load, method, schedule=None, lib_vars=None): if os.path.exists(asset_path): asset_directory.append(asset_path) else: - logger.error(f"Config Error: Asset Directory Does Not Exist: {asset_path}") + logger.error(f"{err_type} Error: Asset Directory Does Not Exist: {asset_path}") current = [] def check_dict(attr, name): @@ -461,25 +466,25 @@ def load_files(files_to_load, method, schedule=None, lib_vars=None): else: current.append((name, file[attr], temp_vars, asset_directory)) else: - logger.error(f"Config Error: {method} {attr} is blank") + logger.error(f"{err_type} Error: {method} {attr} is blank") check_dict("url", "URL") check_dict("git", "Git") check_dict("pmm", "PMM Default") check_dict("repo", "Repo") check_dict("file", "File") - if "folder" in file: + if not single and "folder" in file: if file["folder"] is None: - logger.error(f"Config Error: {method} folder is blank") + logger.error(f"{err_type} Error: {method} folder is blank") elif not os.path.isdir(file["folder"]): - logger.error(f"Config Error: Folder not found: {file['folder']}") + logger.error(f"{err_type} Error: Folder not found: {file['folder']}") else: yml_files = glob_filter(os.path.join(file["folder"], "*.yml")) yml_files.extend(glob_filter(os.path.join(file["folder"], "*.yaml"))) if yml_files: current.extend([("File", yml, temp_vars, asset_directory) for yml in yml_files]) else: - logger.error(f"Config Error: No YAML (.yml|.yaml) files found in {file['folder']}") + logger.error(f"{err_type} Error: No YAML (.yml|.yaml) files found in {file['folder']}") if schedule and "schedule" in file and file["schedule"]: current_time, run_hour, ignore_schedules = schedule @@ -503,7 +508,7 @@ def load_files(files_to_load, method, schedule=None, lib_vars=None): if os.path.exists(file): files.append(("File", file, {}, None)) else: - logger.error(f"Config Error: Path not found: {file}") + logger.error(f"{err_type} Error: Path not found: {file}") return files def check_num(num, is_int=True):