From 8f3794c529fe15931faa605485f6cd0da5454a7f Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Tue, 10 May 2022 14:50:19 -0400 Subject: [PATCH] [82] #710 changed save_missing to save_report --- VERSION | 2 +- docs/config/libraries.md | 38 +++++++------- docs/config/settings.md | 6 +-- docs/metadata/details/setting.md | 2 +- modules/builder.py | 86 +++++++++++++++++--------------- modules/config.py | 14 +++--- modules/library.py | 64 +++++++++++++++++++----- plex_meta_manager.py | 7 +-- 8 files changed, 132 insertions(+), 87 deletions(-) diff --git a/VERSION b/VERSION index acc5c62c..c00001ec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.16.5-develop81 +1.16.5-develop82 diff --git a/docs/config/libraries.md b/docs/config/libraries.md index dbf219fe..eaaf6b11 100644 --- a/docs/config/libraries.md +++ b/docs/config/libraries.md @@ -77,19 +77,19 @@ radarr: The available attributes for each library are as follows: -| Attribute | Values | Default | Required | -|:-------------------------------------------|:---------------------------------------------------------------------------------------------|:--------------------------------------:|:-------------------------------:| -| [`library_name`](#library-name) | Library name (required only when trying to use multiple libraries with the same name) | Base Attribute Name | ❌ | -| [`metadata_path`](#metadata-path) | Location of Metadata YAML files | `/config/<>.yml` | ❌ | -| [`overlay_path`](#overlay-path) | Location of Overlay YAML files | None | ❌ | -| [`missing_path`](#missing-path) | Location to create the YAML file listing missing items for this library | `/config/<>_missing.yml` | ❌ | -| [`schedule`](../metadata/details/schedule) | Use any [schedule option](../metadata/details/schedule) to control when this library is run. | daily | ❌ | -| [`operations`](operations) | Library Operations to run | N/A | ❌ | -| [`settings`](settings) | Any `setting` attribute that overrides a global value | global | ❌ | -| [`plex`](plex) | Any `plex` attribute that overrides a global value | global | ✅ Either here or globally | -| [`radarr`](radarr) | Any `radarr` attribute that overrides a global value | global | ❌ | -| [`sonarr`](sonarr) | Any `sonarr` attribute that overrides a global value | global | ❌ | -| [`tautulli`](tautulli) | Any `tautulli` attribute that overrides a global value | global | ❌ | +| Attribute | Values | Default | Required | +|:-------------------------------------------|:------------------------------------------------------------------------------------------------------|:-------------------------------------:|:-------------------------------:| +| [`library_name`](#library-name) | Library name (required only when trying to use multiple libraries with the same name) | Base Attribute Name | ❌ | +| [`metadata_path`](#metadata-path) | Location of Metadata YAML files | `/config/<>.yml` | ❌ | +| [`overlay_path`](#overlay-path) | Location of Overlay YAML files | None | ❌ | +| [`report_path`](#report-path) | Location to create the YAML file listing added, removed, filtered, and missing items for this library | `/config/<>_report.yml` | ❌ | +| [`schedule`](../metadata/details/schedule) | Use any [schedule option](../metadata/details/schedule) to control when this library is run. | daily | ❌ | +| [`operations`](operations) | Library Operations to run | N/A | ❌ | +| [`settings`](settings) | Any `setting` attribute that overrides a global value | global | ❌ | +| [`plex`](plex) | Any `plex` attribute that overrides a global value | global | ✅ Either here or globally | +| [`radarr`](radarr) | Any `radarr` attribute that overrides a global value | global | ❌ | +| [`sonarr`](sonarr) | Any `sonarr` attribute that overrides a global value | global | ❌ | +| [`tautulli`](tautulli) | Any `tautulli` attribute that overrides a global value | global | ❌ | ### Library Name @@ -157,26 +157,26 @@ libraries: * This will remove all overlays when run and not generate new ones. -### Missing Path +### Report Path -The `missing_path` attribute is used to define where to save the "missing items" YAML file. This file is used to store information about media which is missing from the Plex library compared to what is expected from the Metadata file. +The `report_path` attribute is used to define where to save the YAML Report file. This file is used to store information about what media is added, removed, filtered, and missing from the Plex library compared to what is expected from the Metadata file. If your Metadata file creates a collection with `Movie 1`, `Movie 2` and `Movie 3` but your Plex library only has `Movie 1` and `Movie 3`, then the missing YAML file will be updated to inform the user that `Movie 2` was missing from the library. -The default and recommended path is `/config/<>_missing.yml` where `<>` is the name of the library attribute, as showcased below: +The default and recommended path is `/config/<>report.yml` where `<>` is the name of the library attribute, as showcased below: ```yaml libraries: Movies: - missing_path: /config/Movies_missing.yml + report_path: /config/Movies_report.yml ``` -Alternatively, "missing items" YAML files can be placed in their own directory, as below: +Alternatively, Report YAML files can be placed in their own directory, as below: ```yaml libraries: Movies: - missing_path: /config/missing/Movies.yml + report_path: /config/reports/Movies.yml ``` ## Playlist Files Attribute diff --git a/docs/config/settings.md b/docs/config/settings.md index c1e4d45f..cca6cca8 100644 --- a/docs/config/settings.md +++ b/docs/config/settings.md @@ -46,7 +46,7 @@ The available setting attributes which can be set at each level are outlined bel | [`show_missing`](#show-missing) | ✅ | ✅ | ✅ | | [`only_filter_missing`](#only-filter-missing) | ✅ | ✅ | ✅ | | [`show_missing_assets`](#show-missing-assets) | ✅ | ✅ | ✅ | -| [`save_missing`](#save-missing) | ✅ | ✅ | ✅ | +| [`save_report`](#save-report) | ✅ | ✅ | ✅ | | [`tvdb_language`](#tvdb-language) | ✅ | ❌ | ❌ | | [`ignore_ids`](#ignore-ids) | ✅ | ✅ | ✅ | | [`ignore_imdb_ids`](#ignore-imdb-ids) | ✅ | ✅ | ✅ | @@ -440,8 +440,8 @@ Display missing asset warnings -## Save Missing -Save missing items from collections to a YAML file in the same directory as your Metadata file. +## Save Report +Save a report of the items added, removed, filtered, or missing from collections to a YAML file in the same directory as your Metadata file. diff --git a/docs/metadata/details/setting.md b/docs/metadata/details/setting.md index eb34e450..ed788983 100644 --- a/docs/metadata/details/setting.md +++ b/docs/metadata/details/setting.md @@ -22,7 +22,7 @@ All the following attributes serve various functions as how the collection/playl | `only_filter_missing` | **Description:** Collection/Playlist Level `only_filter_missing` toggle.
**Default:** `only_filter_missing` [settings value](../../config/settings) in the Configuration File
**Values:** `true` or `false` | | `show_filtered` | **Description:** Collection/Playlist level `show_filtered` toggle.
**Default:** `show_filtered` [settings value](../../config/settings) in the Configuration File
**Values:** `true` or `false` | | `show_missing` | **Description:** Collection/Playlist level `show_missing` toggle.
**Default:** `show_missing` [settings value](../../config/settings) in the Configuration File
**Values:** `true` or `false` | -| `save_missing` | **Description:** Collection/Playlist level `save_missing` toggle.
**Default:** `save_missing` [settings value](../../config/settings) in the Configuration File
**Values:** `true` or `false` | +| `save_report` | **Description:** Collection/Playlist level `save_report` toggle.
**Default:** `save_report` [settings value](../../config/settings) in the Configuration File
**Values:** `true` or `false` | | `ignore_ids` | **Description:** Collection/Playlist level `ignore_ids` which is combined with the library and global `ignore_ids`.
**Default:** `ignore_ids` [settings value](../../config/settings) in the Configuration File
**Values:** List or comma-separated String of TMDb/TVDb IDs | | `ignore_imdb_ids` | **Description:** Collection/Playlist level `ignore_imdb_ids` which is combined with the library and global `ignore_imdb_ids`.
**Default:** `ignore_imdb_ids` [settings value](../../config/settings) in the Configuration File
**Values:** List or comma-separated String of IMDb IDs | | `name_mapping` | **Description:** Used to specify the folder name in the [Image Assets Directory](../../home/guides/assets) i.e. if your collection/playlist name contains characters that are not allowed in file paths (i.e. for windows `<`, `>`, `:`, `"`, `/`, `\`, `?`, `*` cannot be in the file path), but you want them in your name you can this to specify the name in the file system.
**Values:** Any String | diff --git a/modules/builder.py b/modules/builder.py index acee8952..2b5369c4 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -31,7 +31,7 @@ summary_details = [ poster_details = ["url_poster", "tmdb_poster", "tmdb_profile", "tvdb_poster", "file_poster"] background_details = ["url_background", "tmdb_background", "tvdb_background", "file_background"] boolean_details = [ - "show_filtered", "show_missing", "save_missing", "missing_only_released", "only_filter_missing", + "show_filtered", "show_missing", "save_report", "missing_only_released", "only_filter_missing", "delete_below_minimum", "asset_folders", "create_asset_folders" ] scheduled_boolean = ["visible_library", "visible_home", "visible_shared"] @@ -126,7 +126,7 @@ year_attributes = plex.year_attributes + ["tmdb_year"] number_attributes = plex.number_attributes + ["tmdb_vote_count"] smart_invalid = ["collection_order", "collection_level"] smart_only = ["collection_filtering"] -smart_url_invalid = ["filters", "run_again", "sync_mode", "show_filtered", "show_missing", "save_missing", "smart_label"] + radarr_details + sonarr_details +smart_url_invalid = ["filters", "run_again", "sync_mode", "show_filtered", "show_missing", "save_report", "smart_label"] + radarr_details + sonarr_details custom_sort_builders = [ "plex_search", "plex_pilots", "tmdb_list", "tmdb_popular", "tmdb_now_playing", "tmdb_top_rated", "tmdb_trending_daily", "tmdb_trending_weekly", "tmdb_discover", "reciperr_list", "trakt_chart", "trakt_userlist", @@ -144,16 +144,16 @@ custom_sort_builders = [ episode_parts_only = ["plex_pilots"] overlay_only = ["overlay", "suppress_overlays"] overlay_attributes = [ - "filters", "limit", "show_missing", "save_missing", "missing_only_released", "minimum_items", "cache_builders", "tmdb_region" + "filters", "limit", "show_missing", "save_report", "missing_only_released", "minimum_items", "cache_builders", "tmdb_region" ] + all_builders + overlay_only parts_collection_valid = [ "filters", "plex_all", "plex_search", "trakt_list", "trakt_list_details", "collection_filtering", "collection_mode", "label", "visible_library", "limit", - "visible_home", "visible_shared", "show_missing", "save_missing", "missing_only_released", "server_preroll", "changes_webhooks", + "visible_home", "visible_shared", "show_missing", "save_report", "missing_only_released", "server_preroll", "changes_webhooks", "item_lock_background", "item_lock_poster", "item_lock_title", "item_refresh", "item_refresh_delay", "imdb_list", "cache_builders", "url_theme", "file_theme", "item_label" ] + episode_parts_only + summary_details + poster_details + background_details + string_details playlist_attributes = [ - "filters", "name_mapping", "show_filtered", "show_missing", "save_missing", + "filters", "name_mapping", "show_filtered", "show_missing", "save_report", "missing_only_released", "only_filter_missing", "delete_below_minimum", "ignore_ids", "ignore_imdb_ids", "server_preroll", "changes_webhooks", "minimum_items", "cache_builders" ] + custom_sort_builders + summary_details + poster_details + radarr_details + sonarr_details @@ -372,7 +372,7 @@ class CollectionBuilder: "show_filtered": self.library.show_filtered, "show_options": self.library.show_options, "show_missing": self.library.show_missing, - "save_missing": self.library.save_missing, + "save_report": self.library.save_report, "missing_only_released": self.library.missing_only_released, "only_filter_missing": self.library.only_filter_missing, "asset_folders": self.library.asset_folders, @@ -396,6 +396,7 @@ class CollectionBuilder: self.filters = [] self.tmdb_filters = [] self.added_items = [] + self.filtered_items = [] self.filtered_keys = {} self.run_again_movies = [] self.run_again_shows = [] @@ -803,7 +804,7 @@ class CollectionBuilder: self.details["collection_mode"] = "hide" self.sync = True - self.do_missing = not self.config.no_missing and (self.details["show_missing"] or self.details["save_missing"] + self.do_missing = not self.config.no_missing and (self.details["show_missing"] or self.details["save_report"] or (self.library.Radarr and self.radarr_details["add_missing"]) or (self.library.Sonarr and self.sonarr_details["add_missing"])) if self.build_collection: @@ -1735,6 +1736,7 @@ class CollectionBuilder: if (self.filters or self.tmdb_filters) and self.details["show_filtered"] is True: logger.info("") logger.info("Filtering Builders:") + filtered_items = [] for i, item in enumerate(items, 1): if not isinstance(item, (Movie, Show, Season, Episode, Artist, Album, Track)): logger.error(f"{self.Type} Error: Item: {item} is an invalid type") @@ -1748,9 +1750,12 @@ class CollectionBuilder: if self.check_filters(item, f"{(' ' * (max_length - len(str(i))))}{i}/{total}"): self.added_items.append(item) else: + filtered_items.append(item) self.filtered_keys[item.ratingKey] = current_title if self.details["show_filtered"] is True: logger.info(f"{name} {self.Type} | X | {current_title}") + if self.details["save_report"] is True and filtered_items: + self.library.add_filtered(self.name, [(i.title, self.library.get_id_from_maps(i.ratingKey)) for i in filtered_items], self.library.is_movie) def build_filter(self, method, plex_filter, display=False, default_sort=None, type_override=None): if display: @@ -2096,7 +2101,7 @@ class CollectionBuilder: spacing = len(str(total)) * 2 + 1 amount_added = 0 amount_unchanged = 0 - playlist_adds = [] + items_added = [] for i, item in enumerate(self.added_items, 1): if self.limit and amount_added + self.beginning_count - len([r for _, r in self.remove_item_map.items() if r is not None]) >= self.limit: logger.info(f"{self.Type} Limit reached") @@ -2109,25 +2114,20 @@ class CollectionBuilder: self.remove_item_map[item.ratingKey] = None amount_unchanged += 1 else: - if self.playlist: - playlist_adds.append(item) - else: + items_added.append(item) + if not self.playlist: self.library.alter_collection(item, name, smart_label_collection=self.smart_label_collection) amount_added += 1 if self.details["changes_webhooks"]: - if item.ratingKey in self.library.movie_rating_key_map: - add_id = self.library.movie_rating_key_map[item.ratingKey] - elif item.ratingKey in self.library.show_rating_key_map: - add_id = self.library.show_rating_key_map[item.ratingKey] - else: - add_id = None - self.notification_additions.append(util.item_set(item, add_id)) - if self.playlist and playlist_adds and not self.obj: - self.obj = self.library.create_playlist(self.name, playlist_adds) + self.notification_additions.append(util.item_set(item, self.library.get_id_from_maps(item.ratingKey))) + if self.playlist and items_added and not self.obj: + self.obj = self.library.create_playlist(self.name, items_added) logger.info("") logger.info(f"Playlist: {self.name} created") - elif self.playlist and playlist_adds: - self.obj.addItems(playlist_adds) + elif self.playlist and items_added: + self.obj.addItems(items_added) + if self.details["save_report"] is True and items_added: + self.library.add_additions(self.name, [(i.title, self.library.get_id_from_maps(i.ratingKey)) for i in items_added], self.library.is_movie) logger.exorcise() logger.info("") logger.info(f"{total} {self.collection_level.capitalize()}{'s' if total > 1 else ''} Processed") @@ -2135,7 +2135,7 @@ class CollectionBuilder: def sync_collection(self): amount_removed = 0 - playlist_removes = [] + items_removed = [] items = [item for _, item in self.remove_item_map.items() if item is not None] if items: logger.info("") @@ -2146,22 +2146,17 @@ class CollectionBuilder: for i, item in enumerate(items, 1): number_text = f"{i}/{total}" logger.info(f"{number_text:>{spacing}} | {self.name} {self.Type} | - | {util.item_title(item)}") - if self.playlist: - playlist_removes.append(item) - else: + items_removed.append(item) + if not self.playlist: self.library.alter_collection(item, self.name, smart_label_collection=self.smart_label_collection, add=False) amount_removed += 1 if self.details["changes_webhooks"]: - if item.ratingKey in self.library.movie_rating_key_map: - remove_id = self.library.movie_rating_key_map[item.ratingKey] - elif item.ratingKey in self.library.show_rating_key_map: - remove_id = self.library.show_rating_key_map[item.ratingKey] - else: - remove_id = None - self.notification_removals.append(util.item_set(item, remove_id)) - if self.playlist and playlist_removes: + self.notification_removals.append(util.item_set(item, self.library.get_id_from_maps(item.ratingKey))) + if self.playlist and items_removed: self.obj.reload() - self.obj.removeItems(playlist_removes) + self.obj.removeItems(items_removed) + if self.details["save_report"] is True and items_removed: + self.library.add_removed(self.name, [(i.title, self.library.get_id_from_maps(i.ratingKey)) for i in items_removed], self.library.is_movie) logger.info("") logger.info(f"{amount_removed} {self.collection_level.capitalize()}{'s' if amount_removed == 1 else ''} Removed") return amount_removed @@ -2265,6 +2260,7 @@ class CollectionBuilder: logger.separator(f"Missing Movies from Library: {self.library.name}", space=False, border=False) logger.info("") missing_movies_with_names = [] + filtered_movies_with_names = [] for missing_id in self.missing_movies: try: movie = self.config.TMDb.get_movie(missing_id) @@ -2277,12 +2273,13 @@ class CollectionBuilder: if self.details["show_missing"] is True: logger.info(f"{self.name} {self.Type} | ? | {current_title} (TMDb: {missing_id})") else: + filtered_movies_with_names.append((current_title, missing_id)) if self.details["show_filtered"] is True and self.details["show_missing"] is True: logger.info(f"{self.name} {self.Type} | X | {current_title} (TMDb: {missing_id})") logger.info("") logger.info(f"{len(missing_movies_with_names)} Movie{'s' if len(missing_movies_with_names) > 1 else ''} Missing") if len(missing_movies_with_names) > 0: - if self.details["save_missing"] is True: + if self.details["save_report"] is True: self.library.add_missing(self.name, missing_movies_with_names, True) if self.run_again or (self.library.Radarr and (self.radarr_details["add_missing"] or "item_radarr_tag" in self.item_details)): missing_tmdb_ids = [missing_id for title, missing_id in missing_movies_with_names] @@ -2301,12 +2298,15 @@ class CollectionBuilder: logger.error(e) if self.run_again: self.run_again_movies.extend(missing_tmdb_ids) + if len(filtered_movies_with_names) > 0 and self.details["save_report"] is True: + self.library.add_filtered(self.name, filtered_movies_with_names, True) if len(self.missing_shows) > 0 and self.library.is_show: if self.details["show_missing"] is True: logger.info("") logger.separator(f"Missing Shows from Library: {self.name}", space=False, border=False) logger.info("") missing_shows_with_names = [] + filtered_shows_with_names = [] for missing_id in self.missing_shows: try: title = self.config.TVDb.get_tvdb_obj(missing_id).title @@ -2318,12 +2318,13 @@ class CollectionBuilder: if self.details["show_missing"] is True: logger.info(f"{self.name} {self.Type} | ? | {title} (TVDb: {missing_id})") else: + filtered_shows_with_names.append((title, missing_id)) if self.details["show_filtered"] is True and self.details["show_missing"] is True: logger.info(f"{self.name} {self.Type} | X | {title} (TVDb: {missing_id})") logger.info("") logger.info(f"{len(missing_shows_with_names)} Show{'s' if len(missing_shows_with_names) > 1 else ''} Missing") if len(missing_shows_with_names) > 0: - if self.details["save_missing"] is True: + if self.details["save_report"] is True: self.library.add_missing(self.name, missing_shows_with_names, False) if self.run_again or (self.library.Sonarr and (self.sonarr_details["add_missing"] or "item_sonarr_tag" in self.item_details)): missing_tvdb_ids = [missing_id for title, missing_id in missing_shows_with_names] @@ -2342,9 +2343,14 @@ class CollectionBuilder: logger.error(e) if self.run_again: self.run_again_shows.extend(missing_tvdb_ids) - if len(self.missing_parts) > 0 and self.library.is_show and self.details["show_missing"] is True: - for missing in self.missing_parts: - logger.info(f"{self.name} {self.Type} | X | {missing}") + if len(filtered_shows_with_names) > 0 and self.details["save_report"] is True: + self.library.add_filtered(self.name, filtered_shows_with_names, False) + if len(self.missing_parts) > 0 and self.library.is_show: + if self.details["show_missing"] is True: + for missing in self.missing_parts: + logger.info(f"{self.name} {self.Type} | ? | {missing}") + if self.details["save_report"] is True: + self.library.add_missing(self.name, self.missing_parts, False) return added_to_radarr, added_to_sonarr def load_collection_items(self): diff --git a/modules/config.py b/modules/config.py index 716f7fe7..baae0b29 100644 --- a/modules/config.py +++ b/modules/config.py @@ -314,7 +314,7 @@ class ConfigFile: "show_options": check_for_attribute(self.data, "show_options", parent="settings", var_type="bool", default=False), "show_missing": check_for_attribute(self.data, "show_missing", parent="settings", var_type="bool", default=True), "show_missing_assets": check_for_attribute(self.data, "show_missing_assets", parent="settings", var_type="bool", default=True), - "save_missing": check_for_attribute(self.data, "save_missing", parent="settings", var_type="bool", default=True), + "save_report": check_for_attribute(self.data, "save_report", parent="settings", var_type="bool", default=True), "tvdb_language": check_for_attribute(self.data, "tvdb_language", parent="settings", default="default"), "ignore_ids": check_for_attribute(self.data, "ignore_ids", parent="settings", var_type="int_list", default_is_none=True), "ignore_imdb_ids": check_for_attribute(self.data, "ignore_imdb_ids", parent="settings", var_type="list", default_is_none=True), @@ -601,7 +601,7 @@ class ConfigFile: params["show_options"] = check_for_attribute(lib, "show_options", parent="settings", var_type="bool", default=self.general["show_options"], do_print=False, save=False) params["show_missing"] = check_for_attribute(lib, "show_missing", parent="settings", var_type="bool", default=self.general["show_missing"], do_print=False, save=False) params["show_missing_assets"] = check_for_attribute(lib, "show_missing_assets", parent="settings", var_type="bool", default=self.general["show_missing_assets"], do_print=False, save=False) - params["save_missing"] = check_for_attribute(lib, "save_missing", parent="settings", var_type="bool", default=self.general["save_missing"], do_print=False, save=False) + params["save_report"] = check_for_attribute(lib, "save_report", parent="settings", var_type="bool", default=self.general["save_report"], do_print=False, save=False) params["missing_only_released"] = check_for_attribute(lib, "missing_only_released", parent="settings", var_type="bool", default=self.general["missing_only_released"], do_print=False, save=False) params["only_filter_missing"] = check_for_attribute(lib, "only_filter_missing", parent="settings", var_type="bool", default=self.general["only_filter_missing"], do_print=False, save=False) params["create_asset_folders"] = check_for_attribute(lib, "create_asset_folders", parent="settings", var_type="bool", default=self.general["create_asset_folders"], do_print=False, save=False) @@ -631,12 +631,12 @@ class ConfigFile: params["split_duplicates"] = check_for_attribute(lib, "split_duplicates", var_type="bool", default=False, save=False, do_print=False) params["radarr_add_all_existing"] = check_for_attribute(lib, "radarr_add_all_existing", var_type="bool", default=False, save=False, do_print=False) params["sonarr_add_all_existing"] = check_for_attribute(lib, "sonarr_add_all_existing", var_type="bool", default=False, save=False, do_print=False) - params["missing_path"] = None - if lib and "missing_path" in lib and lib["missing_path"]: - if os.path.exists(os.path.dirname(os.path.abspath(lib["missing_path"]))): - params["missing_path"] = lib["missing_path"] + params["report_path"] = None + if lib and "report_path" in lib and lib["report_path"]: + if os.path.exists(os.path.dirname(os.path.abspath(lib["report_path"]))): + params["report_path"] = lib["report_path"] else: - logger.error(f"Config Error: Folder {os.path.dirname(os.path.abspath(lib['missing_path']))} does not exist") + logger.error(f"Config Error: Folder {os.path.dirname(os.path.abspath(lib['report_path']))} does not exist") if lib and "operations" in lib and lib["operations"]: if isinstance(lib["operations"], dict): diff --git a/modules/library.py b/modules/library.py index 7a2f4fa5..cebcfb66 100644 --- a/modules/library.py +++ b/modules/library.py @@ -3,7 +3,7 @@ from abc import ABC, abstractmethod from modules import util from modules.meta import MetadataFile, OverlayFile from modules.operations import Operations -from modules.util import Failed, ImageData +from modules.util import Failed from ruamel import yaml logger = util.logger @@ -22,7 +22,6 @@ class Library(ABC): self.overlays = [] self.metadata_files = [] self.overlay_files = [] - self.missing = {} self.movie_map = {} self.show_map = {} self.imdb_map = {} @@ -47,7 +46,8 @@ class Library(ABC): self.image_table_name = self.config.Cache.get_image_table_name(self.original_mapping_name) if self.config.Cache else None self.overlay_folder = os.path.join(self.config.default_dir, "overlays") self.overlay_backup = os.path.join(self.overlay_folder, f"{self.mapping_name} Original Posters") - self.missing_path = params["missing_path"] if params["missing_path"] else os.path.join(self.default_dir, f"{self.mapping_name}_missing.yml") + self.report_path = params["report_path"] if params["report_path"] else os.path.join(self.default_dir, f"{self.mapping_name}_report.yml") + self.report_data = {} self.asset_folders = params["asset_folders"] self.create_asset_folders = params["create_asset_folders"] self.dimensional_asset_rename = params["dimensional_asset_rename"] @@ -68,7 +68,7 @@ class Library(ABC): self.show_options = params["show_options"] self.show_missing = params["show_missing"] self.show_missing_assets = params["show_missing_assets"] - self.save_missing = params["save_missing"] + self.save_report = params["save_report"] self.only_filter_missing = params["only_filter_missing"] self.ignore_ids = params["ignore_ids"] self.ignore_imdb_ids = params["ignore_imdb_ids"] @@ -187,6 +187,13 @@ class Library(ABC): return poster_uploaded, background_uploaded + def get_id_from_maps(self, key): + key = str(key) + if key in self.movie_rating_key_map: + return self.movie_rating_key_map[key] + elif key in self.show_rating_key_map: + return self.show_rating_key_map[key] + @abstractmethod def notify(self, text, collection=None, critical=True): pass @@ -211,17 +218,48 @@ class Library(ABC): def get_all(self, collection_level=None, load=False): pass + def add_additions(self, collection, items, is_movie): + self._add_to_file("Added", collection, items, is_movie) + def add_missing(self, collection, items, is_movie): - if collection not in self.missing: - self.missing[collection] = {} - section = "Movies Missing (TMDb IDs)" if is_movie else "Shows Missing (TVDb IDs)" - if section not in self.missing[collection]: - self.missing[collection][section] = {} - for title, item_id in items: - self.missing[collection][section][int(item_id)] = title - with open(self.missing_path, "w"): pass + self._add_to_file("Missing", collection, items, is_movie) + + def add_removed(self, collection, items, is_movie): + self._add_to_file("Removed", collection, items, is_movie) + + def add_filtered(self, collection, items, is_movie): + self._add_to_file("Filtered", collection, items, is_movie) + + def _add_to_file(self, file_type, collection, items, is_movie): + logger.info(items) + if collection not in self.report_data: + self.report_data[collection] = {} + parts = isinstance(items[0], str) + if parts: + other = f"Parts {file_type}" + section = other + elif is_movie: + other = f"Movies {file_type}" + section = f"{other} (TMDb IDs)" + else: + other = f"Shows {file_type}" + section = f"{other} (TVDb IDs)" + if section not in self.report_data[collection]: + self.report_data[collection][section] = [] if parts else {} + if parts: + self.report_data[collection][section].extend(items) + else: + for title, item_id in items: + if item_id: + self.report_data[collection][section][int(item_id)] = title + else: + if other not in self.report_data[collection]: + self.report_data[collection][other] = [] + self.report_data[collection][other].append(title) + + with open(self.report_path, "w"): pass try: - yaml.round_trip_dump(self.missing, open(self.missing_path, "w", encoding="utf-8")) + yaml.round_trip_dump(self.report_data, open(self.report_path, "w", encoding="utf-8")) except yaml.scanner.ScannerError as e: logger.error(f"YAML Error: {util.tab_new_lines(e)}") diff --git a/plex_meta_manager.py b/plex_meta_manager.py index a642678d..087408a1 100644 --- a/plex_meta_manager.py +++ b/plex_meta_manager.py @@ -187,6 +187,7 @@ def start(attrs): logger.debug(f"--run-metadata-files (PMM_METADATA_FILES): {metadata_files}") logger.debug(f"--ignore-schedules (PMM_IGNORE_SCHEDULES): {ignore_schedules}") logger.debug(f"--ignore-ghost (PMM_IGNORE_GHOST): {ignore_ghost}") + logger.debug(f"--cache-libraries (PMM_CACHE_LIBRARIES): {cache_libraries}") logger.debug(f"--delete-collections (PMM_DELETE_COLLECTIONS): {delete}") logger.debug(f"--resume (PMM_RESUME): {resume}") logger.debug(f"--no-countdown (PMM_NO_COUNTDOWN): {no_countdown}") @@ -244,7 +245,6 @@ def update_libraries(config): logger.debug("") logger.debug(f"Mapping Name: {library.original_mapping_name}") logger.debug(f"Folder Name: {library.mapping_name}") - logger.debug(f"Missing Path: {library.missing_path}") for ad in library.asset_directory: logger.debug(f"Asset Directory: {ad}") logger.debug(f"Asset Folders: {library.asset_folders}") @@ -261,7 +261,8 @@ def update_libraries(config): logger.debug(f"Show Filtered: {library.show_filtered}") logger.debug(f"Show Missing: {library.show_missing}") logger.debug(f"Show Missing Assets: {library.show_missing_assets}") - logger.debug(f"Save Missing: {library.save_missing}") + logger.debug(f"Save Report: {library.save_report}") + logger.debug(f"Report Path: {library.report_path}") logger.debug(f"Clean Bundles: {library.clean_bundles}") logger.debug(f"Empty Trash: {library.empty_trash}") logger.debug(f"Optimize: {library.optimize}") @@ -289,7 +290,7 @@ def update_libraries(config): if not temp_items: temp_items = library.cache_items() - if config.Cache and cache_libraries: + if config.Cache: if list_key: config.Cache.delete_list_ids(list_key) list_key = config.Cache.update_list_cache("library", library.mapping_name, expired, 1)