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: