diff --git a/VERSION b/VERSION index 489f2555..3e4aaece 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.16.5-develop108 +1.16.5-develop109 diff --git a/docs/config/configuration.md b/docs/config/configuration.md index 350d4de5..db9344de 100644 --- a/docs/config/configuration.md +++ b/docs/config/configuration.md @@ -1,6 +1,6 @@ # Configuration File -Plex Meta Manager uses a YAML configuration file; this file contains swettings that deterimine how Plex Meta Manaegr behaves, and the required connection details needed to connect to Plex Media Server, Radarr, Sonarr, and other third-party services via API. +Plex Meta Manager uses a YAML configuration file; this file contains settings that determine how Plex Meta Manager behaves, and the required connection details needed to connect to Plex Media Server, Radarr, Sonarr, and other third-party services via API. By default, and unless otherwise stated, Plex Meta Manager looks for the configuration file within `/config/config.yml` @@ -23,4 +23,219 @@ This table outlines the third-party services that Plex Meta Manager can make use | [`radarr`](radarr) | ❌ | | [`sonarr`](sonarr) | ❌ | | [`trakt`](trakt) | ❌ | -| [`mal`](myanimelist) | ❌ | \ No newline at end of file +| [`mal`](myanimelist) | ❌ | + +# Configuration File Walkthrough + +This example outlines what a "standard" config.yml file might look like when in use. + +
+ Example config.yml file +
+ +```yaml +libraries: + Movies - 4K: + metadata_path: + - file: config/Movies.yml + - git: meisnate12/MovieCharts + TV Shows: + metadata_path: + - file: config/TVShows.yml + - folder: config/TV Shows/ + - git: meisnate12/ShowCharts + Animé: + metadata_path: + - file: config/Anime.yml + Music: + metadata_path: + - file: config/Music.yml +playlist_files: + - file: config/playlists.yml + - git: meisnate12/Playlists +settings: + cache: true + cache_expiration: 60 + asset_directory: config/assets + asset_folders: true + asset_depth: 0 + create_asset_folders: false + dimensional_asset_rename: false + download_url_assets: false + show_missing_season_assets: false + show_missing_episode_assets: false + show_asset_not_needed: true + sync_mode: append + minimum_items: 1 + default_collection_order: + delete_below_minimum: true + delete_not_scheduled: false + run_again_delay: 2 + missing_only_released: false + only_filter_missing: false + show_unmanaged: true + show_filtered: false + show_options: false + show_missing: true + show_missing_assets: true + save_report: true + tvdb_language: eng + ignore_ids: + ignore_imdb_ids: + item_refresh_delay: 0 + playlist_sync_to_users: all + verify_ssl: true +webhooks: + error: + run_start: + run_end: + changes: + version: +plex: + url: http://192.168.1.12:32400 + token: #################### + timeout: 60 + clean_bundles: false + empty_trash: false + optimize: false +tmdb: + apikey: ################################ + language: en +tautulli: + url: http://192.168.1.12:8181 + apikey: ################################ +omdb: + apikey: ######## +notifiarr: + apikey: #################################### +anidb: + username: ###### + password: ###### +radarr: + url: http://192.168.1.12:7878 + token: ################################ + add_missing: false + add_existing: false + root_folder_path: S:/Movies + monitor: true + availability: announced + quality_profile: HD-1080p + tag: + search: false + radarr_path: + plex_path: +sonarr: + url: http://192.168.1.12:8989 + token: ################################ + add_missing: false + add_existing: false + root_folder_path: "S:/TV Shows" + monitor: all + quality_profile: HD-1080p + language_profile: English + series_type: standard + season_folder: true + tag: + search: false + cutoff_search: false + sonarr_path: + plex_path: +trakt: + client_id: ################################################################ + client_secret: ################################################################ + authorization: + # everything below is autofilled by the script + access_token: + token_type: + expires_in: + refresh_token: + scope: public + created_at: +mal: + client_id: ################################ + client_secret: ################################################################ + authorization: + # everything below is autofilled by the script + access_token: + token_type: + expires_in: + refresh_token: +``` +
+ +**Expand the above to see the full config.yml file before continuing.** +
+ +## Library Mappings (`libraries:`) + +`libraries:` is used to tell PMM that the following code relates to Plex libraries. `libraries:` should only be seen once within the configuration file. + +In this specific example there are four Plex libraries that are being connected to: `Movies - 4K`, `TV Shows`, `Animé` and `Music`. These names **must** match the name of the library as it appears within Plex, including any special characters such as the é within `Animé`. + +Using `Movies - 4K:` as an example, `metadata_path:` instructs PMM that the next piece of code is where to look for the [Metadata Files](../../metadata/metadata) which will be covered in the next section. +
+
+ +## Metadata/YAML files (`metadata_path:` mappings) +As can be seen in the original config.yml example, there are three metadata_paths being pointed to for the TV Shows library: +```yaml + TV Shows: + metadata_path: + - file: config/TVShows.yml + - folder: config/TV Shows/ + - git: meisnate12/ShowCharts +``` + +These path types are outlined as follows: +* `- file:` refers to a YAML file which is located within the system that PMM is being run from. + +* `- folder:` refers to a directory containing YAML files which is located within the system that PMM is being run from. + +* `- git:` refers to a YAML file which is hosted on the [GitHub Configs Repo](https://github.com/meisnate12/Plex-Meta-Manager-Configs) unless the user has specified a custom repository within the settings section of the config.yml file. + +Within the above example, PMM will: +* First, look within the root of the PMM directory (also known as `config/`) for a metadata file named `Movies.yml`. If this file does not exist, PMM will skip the entry and move to the next one in the list. +* Then, look within the root of the PMM directory (also known as `config/`) for a directory called `TV Shows`, and then load any metadata/YAML files within that directory. + +* Finally, look at the [meisnate12 folder](https://github.com/meisnate12/Plex-Meta-Manager-Configs/tree/master/meisnate12) within the GitHub Configs Repo for a file called `MovieCharts.yml` which it finds [here](https://github.com/meisnate12/Plex-Meta-Manager-Configs/blob/master/meisnate12/MovieCharts.yml). + +It should be noted that whilst the user should be able to edit any metadata files which are `- file:` or `- folder:` based, they have little to no control over `- git:` metadata files **unless a copy of the YAML file is downloaded and ran locally**. In the above example, if the user downloaded the [MovieCharts.yml file](https://github.com/meisnate12/Plex-Meta-Manager-Configs/blob/master/meisnate12/MovieCharts.yml) from the [GitHub Configs Repo](https://github.com/meisnate12/Plex-Meta-Manager-Configs) and placed it in the root directory of PMM (`config/`), then the metadata_path mapping would be updated to reflect this as follows: +```yaml + Movies - 4K: + metadata_path: + - file: config/Movies.yml + - file: config/MovieCharts.yml <------ HERE +``` + +## Playlists (`playlist_files:` mappings) + +Playlists can be seen as an extension of Libraries in that they are both handled very similarly within PMM: +```yaml +playlist_files: + - file: config/playlists.yml + - git: meisnate12/Playlists +``` + +As with `libraries:`, YAML files are defined to create the Playlists. It should be noted that whilst in `libraries:` when working with `playlist_files:` you call out the libraries being connected to within the Metadata/YAML file as Playlists can combine media from multiple libraries. You can view an example playlists.yml file as follows: + +
+ Example playlists.yml file +
+ +```yaml +playlists: + Marvel Cinematic Universe: + sync_to_users: all + sync_mode: sync + libraries: Movies, TV Shows + trakt_list: https://trakt.tv/users/donxy/lists/marvel-cinematic-universe?sort=rank,asc + summary: Marvel Cinematic Universe In Order + Star Wars Clone Wars Chronological Order: + sync_to_users: all + sync_mode: sync + libraries: Movies, TV Shows + trakt_list: https://trakt.tv/users/tomfin46/lists/star-wars-the-clone-wars-chronological-episode-order +``` +
+ +As can be seen in the above examples, multiple libraries are being used to combine different types of media (movies and tv shows in this case) into one playlist. \ No newline at end of file diff --git a/docs/home/guides/configuration.md b/docs/home/guides/configuration.md deleted file mode 100644 index 9189ce8a..00000000 --- a/docs/home/guides/configuration.md +++ /dev/null @@ -1,213 +0,0 @@ -# Configuration File Walkthrough - -This example outlines what a "standard" config.yml file might look like when in use. - -
- Example config.yml file -
- -```yaml -libraries: - Movies - 4K: - metadata_path: - - file: config/Movies.yml - - git: meisnate12/MovieCharts - TV Shows: - metadata_path: - - file: config/TVShows.yml - - folder: config/TV Shows/ - - git: meisnate12/ShowCharts - Animé: - metadata_path: - - file: config/Anime.yml - Music: - metadata_path: - - file: config/Music.yml -playlist_files: - - file: config/playlists.yml - - git: meisnate12/Playlists -settings: - cache: true - cache_expiration: 60 - asset_directory: config/assets - asset_folders: true - asset_depth: 0 - create_asset_folders: false - dimensional_asset_rename: false - download_url_assets: false - show_missing_season_assets: false - show_missing_episode_assets: false - show_asset_not_needed: true - sync_mode: append - minimum_items: 1 - default_collection_order: - delete_below_minimum: true - delete_not_scheduled: false - run_again_delay: 2 - missing_only_released: false - only_filter_missing: false - show_unmanaged: true - show_filtered: false - show_options: false - show_missing: true - show_missing_assets: true - save_missing: true - tvdb_language: eng - ignore_ids: - ignore_imdb_ids: - item_refresh_delay: 0 - playlist_sync_to_user: all - verify_ssl: true -webhooks: - error: - run_start: - run_end: - changes: -plex: - url: http://192.168.1.12:32400 - token: #################### - timeout: 60 - clean_bundles: false - empty_trash: false - optimize: false -tmdb: - apikey: ################################ - language: en -tautulli: - url: http://192.168.1.12:8181 - apikey: ################################ -omdb: - apikey: ######## -notifiarr: - apikey: #################################### -anidb: - username: ###### - password: ###### -radarr: - url: http://192.168.1.12:7878 - token: ################################ - add_missing: false - add_existing: false - root_folder_path: S:/Movies - monitor: true - availability: announced - quality_profile: HD-1080p - tag: - search: false - radarr_path: - plex_path: -sonarr: - url: http://192.168.1.12:8989 - token: ################################ - add_missing: false - add_existing: false - root_folder_path: "S:/TV Shows" - monitor: all - quality_profile: HD-1080p - language_profile: English - series_type: standard - season_folder: true - tag: - search: false - cutoff_search: false - sonarr_path: - plex_path: -trakt: - client_id: ################################################################ - client_secret: ################################################################ - authorization: - # everything below is autofilled by the script - access_token: - token_type: - expires_in: - refresh_token: - scope: public - created_at: -mal: - client_id: ################################ - client_secret: ################################################################ - authorization: - # everything below is autofilled by the script - access_token: - token_type: - expires_in: - refresh_token: -``` -
- -**Expand the above to see the full config.yml file before continuing.** -
- -## Library Mappings (`libraries:`) - -`libraries:` is used to tell PMM that the following code relates to Plex libraries. `libraries:` should only be seen once within the configuration file. - -In this specific example there are four Plex libraries that are being connected to: `Movies - 4K`, `TV Shows`, `Animé` and `Music`. These names **must** match the name of the library as it appears within Plex, including any special characters such as the é within `Animé`. - -Using `Movies - 4K:` as an example, `metadata_path:` instructs PMM that the next piece of code is where to look for the [Metadata Files](../../metadata/metadata) which will be covered in the next section. -
-
- -## Metadata/YAML files (`metadata_path:` mappings) -As can be seen in the original config.yml example, there are three metadata_paths being pointed to for the TV Shows library: -```yaml - TV Shows: - metadata_path: - - file: config/TVShows.yml - - folder: config/TV Shows/ - - git: meisnate12/ShowCharts -``` - -These path types are outlined as follows: -* `- file:` refers to a YAML file which is located within the system that PMM is being run from. - -* `- folder:` refers to a directory containing YAML files which is located within the system that PMM is being run from. - -* `- git:` refers to a YAML file which is hosted on the [GitHub Configs Repo](https://github.com/meisnate12/Plex-Meta-Manager-Configs) unless the user has specified a custom repository within the settings section of the config.yml file. - -Within the above example, PMM will: -* First, look within the root of the PMM directory (also known as `config/`) for a metadata file named `Movies.yml`. If this file does not exist, PMM will skip the entry and move to the next one in the list. -* Then, look within the root of the PMM directory (also known as `config/`) for a directory called `TV Shows`, and then load any metadata/YAML files within that directory. - -* Finally, look at the [meisnate12 folder](https://github.com/meisnate12/Plex-Meta-Manager-Configs/tree/master/meisnate12) within the GitHub Configs Repo for a file called `MovieCharts.yml` which it finds [here](https://github.com/meisnate12/Plex-Meta-Manager-Configs/blob/master/meisnate12/MovieCharts.yml). - -It should be noted that whilst the user should be able to edit any metadata files which are `- file:` or `- folder:` based, they have little to no control over `- git:` metadata files **unless a copy of the YAML file is downloaded and ran locally**. In the above example, if the user downloaded the [MovieCharts.yml file](https://github.com/meisnate12/Plex-Meta-Manager-Configs/blob/master/meisnate12/MovieCharts.yml) from the [GitHub Configs Repo](https://github.com/meisnate12/Plex-Meta-Manager-Configs) and placed it in the root directory of PMM (`config/`), then the metadata_path mapping would be updated to reflect this as follows: -```yaml - Movies - 4K: - metadata_path: - - file: config/Movies.yml - - file: config/MovieCharts.yml <------ HERE -``` - -## Playlists (`playlist_files:` mappings) - -Playlists can be seen as an extension of Libraries in that they are both handled very similarly within PMM: -```yaml -playlist_files: - - file: config/playlists.yml - - git: meisnate12/Playlists -``` - -As with `libraries:`, YAML files are defined to create the Playlists. It should be noted that whilst in `libraries:` when working with `playlist_files:` you call out the libraries being connected to within the Metadata/YAML file as Playlists can combine media from multiple libraries. You can view an example playlists.yml file as follows: - -
- Example playlists.yml file -
- -```yaml -playlists: - Marvel Cinematic Universe: - sync_to_users: all - sync_mode: sync - libraries: Movies, TV Shows - trakt_list: https://trakt.tv/users/donxy/lists/marvel-cinematic-universe?sort=rank,asc - summary: Marvel Cinematic Universe In Order - Star Wars Clone Wars Chronological Order: - sync_to_users: all - sync_mode: sync - libraries: Movies, TV Shows - trakt_list: https://trakt.tv/users/tomfin46/lists/star-wars-the-clone-wars-chronological-episode-order -``` -
- -As can be seen in the above examples, multiple libraries are being used to combine different types of media (movies and tv shows in this case) into one playlist. \ No newline at end of file diff --git a/docs/home/guides/defaults.md b/docs/home/guides/defaults.md index 8b1d634b..28894c39 100644 --- a/docs/home/guides/defaults.md +++ b/docs/home/guides/defaults.md @@ -136,7 +136,6 @@ libraries: - git: PMM/overlays/streaming - git: PMM/overlays/video_format TV Shows: - missing_path: config/missing/TV_missing metadata_path: - git: PMM/award/choice - git: PMM/award/golden diff --git a/modules/builder.py b/modules/builder.py index 0b2bf0d2..4afceb6f 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -1967,7 +1967,7 @@ class CollectionBuilder: return smart_pair(final_years) elif (attribute in number_attributes + date_attributes + year_attributes and modifier in ["", ".not", ".gt", ".gte", ".lt", ".lte"]) \ or (attribute in plex.tag_attributes and modifier in [".count_gt", ".count_gte", ".count_lt", ".count_lte"]): - return util.parse(self.Type, final, data, datatype="int") + return util.parse(self.Type, final, data, datatype="int", minimum=0) elif attribute in plex.float_attributes and modifier in [".gt", ".gte", ".lt", ".lte"]: return util.parse(self.Type, final, data, datatype="float", minimum=0, maximum=None if attribute == "duration" else 10) elif attribute in plex.boolean_attributes + boolean_filters: diff --git a/modules/meta.py b/modules/meta.py index 4b429337..c790a55a 100644 --- a/modules/meta.py +++ b/modules/meta.py @@ -143,23 +143,21 @@ class DataFile: default = {} if "default" in template: - if template["default"]: - if isinstance(template["default"], dict): - for dv in template["default"]: - if str(dv) not in optional: - if template["default"][dv] is not None: - final_value = template["default"][dv] - for key, value in variables.items(): - if f"<<{key}>>" in str(final_value): - final_value = str(final_value).replace(f"<<{key}>>", str(value)) - default[dv] = final_value - default[f"{dv}_encoded"] = requests.utils.quote(str(final_value)) - else: - raise Failed(f"{self.data_type} Error: template default sub-attribute {dv} is blank") - else: - raise Failed(f"{self.data_type} Error: template sub-attribute default is not a dictionary") - else: + if not template["default"]: raise Failed(f"{self.data_type} Error: template sub-attribute default is blank") + if not isinstance(template["default"], dict): + raise Failed(f"{self.data_type} Error: template sub-attribute default is not a dictionary") + for dv in template["default"]: + for k, v in variables.items(): + if f"<<{k}>>" in dv: + dv = dv.replace(f"<<{k}>>", str(v)) + if dv not in optional: + final_value = template["default"][dv] + for key, value in variables.items(): + if f"<<{key}>>" in str(final_value): + final_value = str(final_value).replace(f"<<{key}>>", str(value)) + default[dv] = final_value + default[f"{dv}_encoded"] = requests.utils.quote(str(final_value)) if "optional" in template: if template["optional"]: @@ -210,26 +208,24 @@ class DataFile: else: final_data = _data def scan_text(og_txt, var, var_value): - if str(og_txt) == f"<<{var}>>": + if og_txt is None: + return og_txt + elif str(og_txt) == f"<<{var}>>": return var_value elif f"<<{var}>>" in str(og_txt): return str(og_txt).replace(f"<<{var}>>", str(var_value)) + else: + return og_txt for option in optional: if option not in variables and f"<<{option}>>" in str(final_data): raise Failed - clean = False - while not clean: - clean = True + for i in range(2): for variable, variable_data in variables.items(): - var_data = None if (variable == "collection_name" or variable == "playlist_name") and _method in ["radarr_tag", "item_radarr_tag", "sonarr_tag", "item_sonarr_tag"]: - var_data = scan_text(final_data, variable, variable_data.replace(",", "")) + final_data = scan_text(final_data, variable, variable_data.replace(",", "")) elif variable != "name": - var_data = scan_text(final_data, variable, variable_data) - if var_data: - final_data = var_data - clean = False + final_data = scan_text(final_data, variable, variable_data) for dm, dd in default.items(): default_data = scan_text(final_data, dm, dd) if default_data: @@ -238,9 +234,6 @@ class DataFile: for method_name, attr_data in template.items(): if method_name not in data and method_name not in ["default", "optional", "move_collection_prefix", "move_prefix"]: - if attr_data is None: - logger.error(f"Template Error: template attribute {method_name} is blank") - continue if method_name in new_attributes: logger.warning(f"Template Warning: template attribute: {method_name} from {variables['name']} skipped") else: