diff --git a/VERSION b/VERSION index 1f345ccc..adcc7657 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.16.0-develop17 +1.16.0-develop18 diff --git a/docs/metadata/dynamic.md b/docs/metadata/dynamic.md index f7be3300..2bc6f1bf 100644 --- a/docs/metadata/dynamic.md +++ b/docs/metadata/dynamic.md @@ -24,7 +24,7 @@ dynamic_collections: By default, the collections generated will be named for the thing being used to create them; things like genres, countries, actors or even Trakt List Names. -There are many attributes that can change the titles, including `title_format`, `remove_suffix`, `remove_prefix`, `pre_format_override`, and `post_format_override` all detailed below. +There are many attributes that can change the titles, including `title_format`, `remove_suffix`, `remove_prefix`, `key_name_override`, and `title_override` all detailed below. ## Dynamic Keys & Key Names @@ -52,7 +52,7 @@ dynamic_collections: - Horror ``` -* Using the `pre_format_override` attribute to change the formatting of "France" to "French" so that a collection can be named "French Cinema" instead of simply "France" +* Using the `key_name_override` attribute to change the formatting of "France" to "French" so that a collection can be named "French Cinema" instead of simply "France" * This particular example also uses the `title_format` attribute to manipulate the naming convention of the collections. ```yaml @@ -60,7 +60,7 @@ dynamic_collections: Countries: # mapping name does not matter, just needs to be unique type: country title_format: <> Cinema - pre_format_override: + key_name_override: France: French ``` @@ -81,23 +81,23 @@ dynamic_collections: ## Attributes -| Attribute | Description | Required | -|:------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------|:-----------------:| -| [`type`](#type--data) | Type of Dynamic Collection to be created. | ✅ | -| [`data`](#type--data) | Data to determine how dynamic collections with a certain `type` are created. | Depends on `type` | -| [`exclude`](#exclude) | Exclude this list of keys from being created into collections. | ❌ | -| [`addons`](#addons) | Defines how multiple keys can be combined under a parent key. | ❌ | -| [`template`](#template) | Name of the template to use for these dynamic collections. | ❌ | -| [`template_variables`](#template-variables) | Defines how template variables can be defined by key. | ❌ | -| [`remove_suffix`](#remove-prefixsuffix) | Removes the defined suffixes from the key before it's used in the collection title. | ❌ | -| [`remove_prefix`](#remove-prefixsuffix) | Removes the defined prefixes from the key before it's used in the collection title. | ❌ | -| [`title_format`](#title-format) | This is the format for the collection titles. | ❌ | -| [`pre_format_override`](#pre-format-override) | Defines how titles can be overridden before they are formatted into collection titles. | ❌ | -| [`post_format_override`](#post-format-override) | Defines how collection titles can be overridden ignoring title formatting. | ❌ | -| [`test`](#test) | Will add `test: true` to all collections for test runs. | ❌ | -| [`sync`](#sync) | Will remove dynamic collections that are no longer in the creation list. | ❌ | -| [`include`](#include) | Define a list of keys to be made into collections. | ❌ | -| [`other_name`](#other-name) | Used in combination with `include`. When defined, all keys not in `include` or `addons` will be combined into this collection. | ❌ | +| Attribute | Description | Required | +|:--------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------|:-----------------:| +| [`type`](#type--data) | Type of Dynamic Collection to be created. | ✅ | +| [`data`](#type--data) | Data to determine how dynamic collections with a certain `type` are created. | Depends on `type` | +| [`exclude`](#exclude) | Exclude this list of keys from being created into collections. | ❌ | +| [`addons`](#addons) | Defines how multiple keys can be combined under a parent key. | ❌ | +| [`template`](#template) | Name of the template to use for these dynamic collections. | ❌ | +| [`template_variables`](#template-variables) | Defines how template variables can be defined by key. | ❌ | +| [`remove_suffix`](#remove-prefixsuffix) | Removes the defined suffixes from the key before it's used in the collection title. | ❌ | +| [`remove_prefix`](#remove-prefixsuffix) | Removes the defined prefixes from the key before it's used in the collection title. | ❌ | +| [`title_format`](#title-format) | This is the format for the collection titles. | ❌ | +| [`key_name_override`](#key-name-override) | Defines how key names can be overridden before they are formatted into collection titles. | ❌ | +| [`title_override`](#title-override) | Defines how collection titles can be overridden ignoring title formatting. | ❌ | +| [`test`](#test) | Will add `test: true` to all collections for test runs. | ❌ | +| [`sync`](#sync) | Will remove dynamic collections that are no longer in the creation list. | ❌ | +| [`include`](#include) | Define a list of keys to be made into collections. | ❌ | +| [`other_name`](#other-name) | Used in combination with `include`. When defined, all keys not in `include` or `addons` will be combined into this collection. | ❌ | ## Type & Data @@ -110,6 +110,7 @@ Depending on the `type` of dynamic collection, `data` is used to specify the opt | [`tmdb_collection`](#tmdb-collection) | Create a collection for each TMDb Collection associated with an item in the library | ❌ | ✅ | ❌ | ❌ | ❌ | | [`tmdb_popular_people`](#tmdb-popular-people) | Create a collection for each actor found on [TMDb's Popular People List](https://www.themoviedb.org/person) | ✅ | ✅ | ✅ | ❌ | ❌ | | [`original_language`](#original-language) | Create a collection for each TMDb original language associated with an item in the library | ❌ | ✅ | ✅ | ❌ | ❌ | +| [`origin_country`](#origin-country) | Create a collection for each TMDb origin country associated with an item in the library | ❌ | ❌ | ✅ | ❌ | ❌ | | [`trakt_user_lists`](#trakt-user-lists) | Create a collection for each list from specific trakt users | ✅ | ✅ | ✅ | ❌ | ❌ | | [`trakt_liked_lists`](#trakt-liked-lists) | Create a collection for each list the authenticated trakt user likes | ❌ | ✅ | ✅ | ❌ | ❌ | | [`trakt_people_list`](#trakt-people-lists) | Create a collection for each actor found in the trakt list | ✅ | ✅ | ✅ | ❌ | ❌ | @@ -143,7 +144,7 @@ Create collections based on the TMDb Collections associated with items in the li TMDb Collection ID - Titles + Key Names TMDb Collection Title @@ -191,7 +192,7 @@ Create collections based on each actor found on [TMDb's Popular People List](htt TMDb Person ID - Titles + Key Names TMDb Person Name @@ -241,7 +242,7 @@ Create collections based on the TMDb original language associated with items in ISO 639-1 Code - Titles + Key Names ISO Language Name @@ -271,6 +272,53 @@ dynamic_collections: type: original_language ``` +### Origin Country + +Create collections based on the TMDb origin country associated with items in the library. + + + + + + + + + + + + + + + + + + + + + + + + + + +
type Optionorigin_country
data ValueNot Used
KeysISO 3166-1 alpha-2 country code
Key NamesISO Country Name
Default title_format<<title>> <<library_type>>s
Default Template + +```yaml +default_template: + plex_all: true + filters: + origin_country: <> +``` + +
+ +#### Example: Create collection for every TMDb Origin Country found in the library. + +```yaml +dynamic_collections: + TMDb Countries: # This name is the mapping name + type: origin_country +``` ### Trakt User Lists @@ -292,7 +340,7 @@ Create collections for each of the Trakt lists for the specified users. Use `me` Trakt List URL - Titles + Key Names Trakt List Title @@ -343,7 +391,7 @@ Create collections for each of the Trakt lists that the authenticated user has l Trakt List URL - Titles + Key Names Trakt List Title @@ -391,7 +439,7 @@ Create collections for each of the people found within Trakt lists that the user TMDb Person ID - Titles + Key Names TMDb Person Name @@ -463,7 +511,7 @@ Create a collection for each actor found in the library. TMDb Person ID - Titles + Key Names TMDb Person Name @@ -490,6 +538,33 @@ default_template: * `minimum` determines the minimum number of times the actor must appear within `depth` for the collection to be created. * `limit` determines the number of actor collection to max out at. (i.e. if to make collections for the top 25 actors) +#### Example: + +* Create a collection for the top 25 actors who appear in the top 5 billing credits of movies + +```yaml +dynamic_collections: + Top Actors: # mapping name does not matter just needs to be unique + type: actor + data: + depth: 5 + limit: 25 +``` + +#### Example: + +* Create a collection for actors who appear in the top 5 billing credits of movies +* Only create the collection if they are in the top 5 billing credits of at least 20 movies + +```yaml +dynamic_collections: + Actors: # mapping name does not matter just needs to be unique + type: actor + data: + depth: 5 + minimum: 20 +``` + ### Director Create a collection for each director found in the library. @@ -530,7 +605,7 @@ Create a collection for each director found in the library. TMDb Person ID - Titles + Key Names TMDb Person Name @@ -557,6 +632,33 @@ default_template: * `minimum` determines the minimum number of times the director must appear within `depth` for the collection to be created. * `limit` determines the number of director collection to max out at. (i.e. if to make collections for the top 25 directors) +#### Example: + +* Create a collection for the top 5 directors who appear in the top director credit of movies + +```yaml +dynamic_collections: + Top Directors: # mapping name does not matter just needs to be unique + type: director + data: + depth: 1 + limit: 5 +``` + +#### Example: + +* Create a collection for directors who appear in the top director credits of movies +* Only create the collection if they are in the top director credits of at least 10 movies + +```yaml +dynamic_collections: + Directors: # mapping name does not matter just needs to be unique + type: director + data: + depth: 1 + minimum: 10 +``` + ### Writer Create a collection for each writer found in the library. @@ -597,7 +699,7 @@ Create a collection for each writer found in the library. TMDb Person ID - Titles + Key Names TMDb Person Name @@ -624,6 +726,33 @@ default_template: * `minimum` determines the minimum number of times the writer must appear within `depth` for the collection to be created. * `limit` determines the number of writer collection to max out at. (i.e. if to make collections for the top 25 writers) +#### Example: + +* Create a collection for the top 5 writers who appear in the top writer credit of movies + +```yaml +dynamic_collections: + Top Writers: # mapping name does not matter just needs to be unique + type: writer + data: + depth: 1 + limit: 5 +``` + +#### Example: + +* Create a collection for writers who appear in the top writer credits of movies +* Only create the collection if they are in the top writer credits of at least 10 movies + +```yaml +dynamic_collections: + Writers: # mapping name does not matter just needs to be unique + type: writer + data: + depth: 1 + minimum: 10 +``` + ### Producer Create a collection for each producer found in the library. @@ -664,7 +793,7 @@ Create a collection for each producer found in the library. TMDb Person ID - Titles + Key Names TMDb Person Name @@ -693,29 +822,29 @@ default_template: #### Example: -* Create a collection for the top 25 actors who appear in the top 5 billing credits of movies +* Create a collection for the top 5 producers who appear in the top producer credit of movies ```yaml dynamic_collections: - Top Actors: # mapping name does not matter just needs to be unique - type: actor + Top Producers: # mapping name does not matter just needs to be unique + type: producer data: - depth: 5 - limit: 25 + depth: 1 + limit: 5 ``` #### Example: -* Create a collection for actors who appear in the top 5 billing credits of movies -* Only create the collection if they are in the top 5 billing credits of at least 20 movies +* Create a collection for producers who appear in the top producer credits of movies +* Only create the collection if they are in the top producer credits of at least 10 movies ```yaml dynamic_collections: - Actors: # mapping name does not matter just needs to be unique - type: actor + Producers: # mapping name does not matter just needs to be unique + type: producers data: - depth: 5 - minimum: 20 + depth: 1 + minimum: 10 ``` ### Genre @@ -736,7 +865,7 @@ Create a collection for each genre found in the library. Genre - Titles + Key Names Genre @@ -802,7 +931,7 @@ Create a collection for each year found in the library. Year - Titles + Key Names Year @@ -861,7 +990,7 @@ Create a collection for each decade found in the library Decade - Titles + Key Names Decade @@ -896,7 +1025,7 @@ dynamic_collections: Decades: # mapping name does not matter just needs to be unique type: decade title_format: Top <> <>s - post_format_override: + title_override: 2020: Top 2020 Movies (so far) ``` @@ -918,7 +1047,7 @@ Create a collection for each country found in the library Country - Titles + Key Names Country @@ -946,14 +1075,14 @@ default_template: * Create a collection for the top movies from each country found in the library * Name the collection Top [Country] Cinema -* The `pre_format_override` attribute is used here in combination with the `title_format` to change the collection name from "France" which would be the default title, to "Top French Cinema" +* The `key_name_override` attribute is used here in combination with the `title_format` to change the collection name from "France" which would be the default title, to "Top French Cinema" ```yaml dynamic_collections: Countries: # mapping name does not matter just needs to be unique type: country title_format: Top <> Cinema - pre_format_override: + key_name_override: France: French Germany: German India: Indian @@ -977,7 +1106,7 @@ Create a collection for each network found in the library. Network - Titles + Key Names Network @@ -1038,7 +1167,7 @@ Create a collection for each mood found in the library. Mood - Titles + Key Names Mood @@ -1101,7 +1230,7 @@ Create a collection for each style found in the library. Style - Titles + Key Names Style @@ -1252,11 +1381,11 @@ dynamic_collections: title_format: Top 50 <> <>s ``` -## Pre Format Override +## Key Name Override -Defines how titles can be overridden before they are formatted into collection titles. +Defines how key names can be overridden before they are formatted into collection titles. -This example uses the `pre_format_override` attribute to change the formatting of "France" to "French" so that a collection can be named "French Cinema" instead of simply "France" +This example uses the `key_name_override` attribute to change the formatting of "France" to "French" so that a collection can be named "French Cinema" instead of simply "France" * This particular example also uses the `title_format` attribute to manipulate the naming convention of the collections. ```yaml @@ -1264,22 +1393,22 @@ dynamic_collections: Countries: # mapping name does not matter, just needs to be unique type: country title_format: <> Cinema - pre_format_override: + key_name_override: France: French ``` -## Post Format Override +## Title Override Defines how collection titles can be overridden ignoring title formatting. -Here's an example using `post_format_override` that will override the TMDb Star Wars collection which has an TMDb ID of `10` with `Star Wars Universe. +Here's an example using `title_override` that will override the TMDb Star Wars collection which has an TMDb ID of `10` with `Star Wars Universe. ```yaml dynamic_collections: TMDb Collections: # mapping name does not matter, just needs to be unique type: tmdb_collections remove_suffix: "Collection" - post_format_override: + title_override: 10: Star Wars Universe ``` diff --git a/docs/metadata/filters.md b/docs/metadata/filters.md index f015be7e..a462af74 100644 --- a/docs/metadata/filters.md +++ b/docs/metadata/filters.md @@ -11,6 +11,7 @@ You can use the `plex_all: true` builder to filter from your entire library. **Filters can be very slow. Try to build or narrow your items using [Plex Search](builders/plex.md#plex-search) if possible.** ## String Filters + String filters can be used with either no modifier or with `.not`, `.is`, `.isnot`, `.begins`, `.ends`, or `.regex`. String filters can take multiple values **only as a list**. @@ -39,12 +40,11 @@ String filters can take multiple values **only as a list**. | `audio_track_title` | Uses the audio track titles to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ## Tag Filters + Tag filters can be used with either no modifier or with `.not`. Tag filters can take multiple values as a **list or a comma-separated string**. -The `original_language` and `tmdb_genre` filters will also filter out movies/shows from being added to Radarr/Sonarr. - ### Modifier | Tag Modifier | Description | @@ -58,28 +58,33 @@ The `original_language` and `tmdb_genre` filters will also filter out movies/sho ### Attribute -| Tag Filters | Description | Movies | Shows | Seasons | Episodes | Artists | Albums | Track | -|:--------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:| -| `actor` | Uses the actor tags to match | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `collection` | Uses the collection tags to match | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `content_rating` | Uses the content rating tags to match | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `network` | Uses the network tags to match | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `country` | Uses the country tags to match | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | -| `director` | Uses the director tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `genre` | Uses the genre tags to match | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | -| `tmdb_genre` | Uses the genre from TMDb to match | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `label` | Uses the label tags to match | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | -| `producer` | Uses the actor tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `year` | Uses the year tag to match | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | -| `writer` | Uses the writer tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `resolution` | Uses the resolution tag to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `audio_language` | Uses the audio language tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `subtitle_language` | Uses the subtitle language tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `original_language` | Uses TMDb original language [ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to match
Example: `original_language: en, ko` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `tmdb_status` | Uses TMDb Status to match
**Values:** `returning`, `planned`, `production`, `ended`, `canceled`, `pilot` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `tmdb_type` | Uses TMDb Type to match
**Values:** `documentary`, `news`, `production`, `miniseries`, `reality`, `scripted`, `talk_show`, `video` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| Tag Filters | Description | Movies | Shows | Seasons | Episodes | Artists | Albums | Track | +|:--------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:| +| `actor` | Uses the actor tags to match | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `collection` | Uses the collection tags to match | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `content_rating` | Uses the content rating tags to match | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `network` | Uses the network tags to match | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `country` | Uses the country tags to match | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | +| `director` | Uses the director tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `genre` | Uses the genre tags to match | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | +| `tmdb_genre`1 | Uses the genre from TMDb to match | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `tmdb_keyword`1 | Uses the keyword from TMDb to match | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `label` | Uses the label tags to match | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | +| `producer` | Uses the actor tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `year` | Uses the year tag to match | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | +| `writer` | Uses the writer tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `resolution` | Uses the resolution tag to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `audio_language` | Uses the audio language tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `subtitle_language` | Uses the subtitle language tags to match | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `original_language`1 | Uses TMDb original language [ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to match
Example: `original_language: en, ko` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `origin_country`1 | Uses TMDb origin country [ISO 3166-1 alpha-2 codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) to match
Example: `origin_country: us` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `tmdb_status`1 | Uses TMDb Status to match
**Values:** `returning`, `planned`, `production`, `ended`, `canceled`, `pilot` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `tmdb_type`1 | Uses TMDb Type to match
**Values:** `documentary`, `news`, `production`, `miniseries`, `reality`, `scripted`, `talk_show`, `video` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | + +1 Also filters out missing movies/shows from being added to Radarr/Sonarr. These Values also cannot use the `count` modifiers. ## Boolean Filters + Boolean Filters have no modifiers. ### Attribute @@ -90,12 +95,11 @@ Boolean Filters have no modifiers. | `has_overlay` | Matches every item that has or does not have an overlay | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ## Date Filters + Date filters can be used with either no modifier or with `.not`, `.before`, `.after`, or `.regex`. Date filters can **NOT** take multiple values. -The `first_episode_aired` and `last_episode_aired` filters will also filter out movies/shows from being added to Radarr/Sonarr. - ### Modifier | Date Modifier | Description | Format | @@ -108,21 +112,22 @@ The `first_episode_aired` and `last_episode_aired` filters will also filter out ### Attribute -| Date Filters | Description | Movies | Shows | Seasons | Episodes | Artists | Albums | Track | -|:----------------------|:----------------------------------------------------------------|:--------:|:-------:|:--------:|:--------:|:--------:|:--------:|:--------:| -| `release` | Uses the release date attribute (originally available) to match | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | -| `added` | Uses the date added attribute to match | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `last_played` | Uses the date last played attribute to match | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `first_episode_aired` | Uses the first episode aired date to match | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `last_episode_aired` | Uses the last episode aired date to match | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| Date Filters | Description | Movies | Shows | Seasons | Episodes | Artists | Albums | Track | +|:----------------------------------|:----------------------------------------------------------------|:--------:|:-------:|:--------:|:--------:|:--------:|:--------:|:--------:| +| `release` | Uses the release date attribute (originally available) to match | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | +| `added` | Uses the date added attribute to match | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `last_played` | Uses the date last played attribute to match | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `first_episode_aired`1 | Uses the first episode aired date to match | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `last_episode_aired`1 | Uses the last episode aired date to match | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | + +1 Also filters out missing movies/shows from being added to Radarr/Sonarr. ## Number Filters + Number filters must use `.gt`, `.gte`, `.lt`, or `.lte` as a modifier. Number filters can **NOT** take multiple values. -The `tmdb_vote_count` and `tmdb_year` filters will also filter out movies/shows from being added to Radarr/Sonarr. - ### Modifier | Number Modifier | Description | Format | @@ -134,18 +139,21 @@ The `tmdb_vote_count` and `tmdb_year` filters will also filter out movies/shows ### Attribute -| Number Filters | Description | Movies | Shows | Seasons | Episodes | Artists | Albums | Track | -|:------------------|:---------------------------------------------------------------------|:-------:|:-------:|:--------:|:--------:|:--------:|:--------:|:--------:| -| `year` | Uses the year attribute to match
minimum: `1` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | -| `tmdb_year` | Uses the year on TMDb to match
minimum: `1` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `critic_rating` | Uses the critic rating attribute to match
`0.0` - `10.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | -| `audience_rating` | Uses the audience rating attribute to match
`0.0` - `10.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | -| `user_rating` | Uses the user rating attribute to match
`0.0` - `10.0` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `tmdb_vote_count` | Uses the tmdb vote count to match
minimum: `1` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| `plays` | Uses the plays attribute to match
minimum: `1` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `duration` | Uses the duration attribute to match using minutes
minimum: `0.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | +| Number Filters | Description | Movies | Shows | Seasons | Episodes | Artists | Albums | Track | +|:------------------------------|:---------------------------------------------------------------------|:-------:|:-------:|:--------:|:--------:|:--------:|:--------:|:--------:| +| `year` | Uses the year attribute to match
minimum: `1` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | +| `tmdb_year`1 | Uses the year on TMDb to match
minimum: `1` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `critic_rating` | Uses the critic rating attribute to match
`0.0` - `10.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | +| `audience_rating` | Uses the audience rating attribute to match
`0.0` - `10.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | +| `user_rating` | Uses the user rating attribute to match
`0.0` - `10.0` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `tmdb_vote_count`1 | Uses the tmdb vote count to match
minimum: `1` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| `plays` | Uses the plays attribute to match
minimum: `1` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `duration` | Uses the duration attribute to match using minutes
minimum: `0.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | + +1 Also filters out missing movies/shows from being added to Radarr/Sonarr. ## Special Filters + Special Filters each have their own set of rules for how they're used. ### Attribute diff --git a/modules/builder.py b/modules/builder.py index f540d330..fb4b9d5e 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -132,7 +132,7 @@ filters_by_type = { "movie_show": ["studio", "original_language", "has_overlay", "tmdb_vote_count", "tmdb_year", "tmdb_genre", "tmdb_title", "tmdb_keyword"], "movie_episode": ["director", "producer", "writer", "resolution", "audio_language", "subtitle_language", "has_dolby_vision"], "movie_artist": ["country"], - "show": ["tmdb_status", "tmdb_type", "network", "first_episode_aired", "last_episode_aired"], + "show": ["tmdb_status", "tmdb_type", "origin_country", "network", "first_episode_aired", "last_episode_aired"], "album": ["record_label"] } filters = { @@ -144,11 +144,14 @@ filters = { "album": [item for check, sub in filters_by_type.items() for item in sub if "album" in check], "track": [item for check, sub in filters_by_type.items() for item in sub if "track" in check] } -tmdb_filters = ["original_language", "tmdb_vote_count", "tmdb_year", "tmdb_keyword", "tmdb_genre", "first_episode_aired", "last_episode_aired", "tmdb_status", "tmdb_type", "tmdb_title"] +tmdb_filters = [ + "original_language", "origin_country", "tmdb_vote_count", "tmdb_year", "tmdb_keyword", "tmdb_genre", + "first_episode_aired", "last_episode_aired", "tmdb_status", "tmdb_type", "tmdb_title" +] string_filters = ["title", "summary", "studio", "record_label", "filepath", "audio_track_title", "tmdb_title"] string_modifiers = ["", ".not", ".is", ".isnot", ".begins", ".ends", ".regex"] tag_filters = [ - "actor", "collection", "content_rating", "country", "director", "network", "genre", "label", "producer", "year", + "actor", "collection", "content_rating", "country", "director", "network", "genre", "label", "producer", "year", "origin_country", "writer", "original_language", "resolution", "audio_language", "subtitle_language", "tmdb_keyword", "tmdb_genre", "tmdb_status", "tmdb_type" ] tag_modifiers = ["", ".not", ".count_gt", ".count_gte", ".count_lt", ".count_lte"] @@ -1716,7 +1719,7 @@ class CollectionBuilder: return valid_regex elif attribute in plex.string_attributes + string_filters and modifier in ["", ".not", ".is", ".isnot", ".begins", ".ends"]: return smart_pair(util.get_list(data, split=False)) - elif attribute in ["original_language", "tmdb_keyword"]: + elif attribute in ["original_language", "origin_country", "tmdb_keyword"]: return util.get_list(data, lower=True) elif attribute in ["filepath", "tmdb_genre"]: return util.get_list(data) @@ -1909,6 +1912,8 @@ class CollectionBuilder: check_value = discover_types[item.type] elif filter_attr == "original_language": check_value = item.original_language.iso_639_1 + else: + raise Failed if (modifier == ".not" and check_value in filter_data) or (modifier == "" and check_value not in filter_data): return False elif filter_attr in ["first_episode_aired", "last_episode_aired"]: @@ -1927,13 +1932,15 @@ class CollectionBuilder: attr = item.release_date.year if is_movie else item.first_air_date.year if util.is_number_filter(attr, modifier, filter_data): return False - elif filter_attr == "tmdb_genre": - attrs = [g.name for g in item.genres] - if (not list(set(filter_data) & set(attrs)) and modifier == "") \ - or (list(set(filter_data) & set(attrs)) and modifier == ".not"): - return False - elif filter_attr == "tmdb_keyword": - attrs = [k.name for k in item.keywords] + elif filter_attr in ["tmdb_genre", "tmdb_keyword", "origin_country"]: + if filter_attr == "tmdb_genre": + attrs = [g.name for g in item.genres] + elif filter_attr == "tmdb_keyword": + attrs = [k.name for k in item.keywords] + elif filter_attr == "origin_country": + attrs = [c.iso_3166_1 for c in item.origin_countries] + else: + raise Failed if (not list(set(filter_data) & set(attrs)) and modifier == "") \ or (list(set(filter_data) & set(attrs)) and modifier == ".not"): return False diff --git a/modules/meta.py b/modules/meta.py index 2074a36c..6fb95083 100644 --- a/modules/meta.py +++ b/modules/meta.py @@ -14,7 +14,7 @@ all_auto = ["genre"] ms_auto = ["actor", "year", "original_language", "tmdb_popular_people", "trakt_user_lists", "trakt_liked_lists", "trakt_people_list"] auto = { "Movie": ["tmdb_collection", "decade", "country", "director", "producer", "writer"] + all_auto + ms_auto, - "Show": ["network"] + all_auto + ms_auto, + "Show": ["network", "origin_country"] + all_auto + ms_auto, "Artist": ["mood", "style", "country"] + all_auto, "Video": ["country"] + all_auto } @@ -24,6 +24,7 @@ default_templates = { "producer": {"tmdb_person": f"<>", "plex_search": {"all": {"producer": "tmdb"}}}, "writer": {"tmdb_person": f"<>", "plex_search": {"all": {"writer": "tmdb"}}}, "original_language": {"plex_all": True, "filters": {"original_language": "<>"}}, + "origin_country": {"plex_all": True, "filters": {"origin_country": "<>"}}, "tmdb_collection": {"tmdb_collection_details": "<>"}, "trakt_user_lists": {"trakt_list_details": "<>"}, "trakt_liked_lists": {"trakt_list_details": "<>"}, @@ -308,6 +309,19 @@ class MetadataFile(DataFile): auto_list[tmdb_item.original_language.iso_639_1] = tmdb_item.original_language.english_name logger.exorcise() default_title_format = "<> <>s" + elif auto_type == "origin_country": + if not all_items: + all_items = library.get_all() + for i, item in enumerate(all_items, 1): + logger.ghost(f"Processing: {i}/{len(all_items)} {item.title}") + tmdb_id, tvdb_id, imdb_id = library.get_ids(item) + tmdb_item = config.TMDb.get_item(item, tmdb_id, tvdb_id, imdb_id, is_movie=library.type == "Movie") + if tmdb_item and tmdb_item.origin_countries: + for country in tmdb_item.origin_countries: + if country.iso_3166_1 not in exclude and country.name not in exclude: + auto_list[country.iso_3166_1] = country.name + logger.exorcise() + default_title_format = "<> <>s" elif auto_type in ["actor", "director", "writer", "producer"]: people = {} if "data" in methods: @@ -372,8 +386,12 @@ class MetadataFile(DataFile): if "<>" not in title_format and "<>" not in title_format: logger.error(f"Config Error: <<key_name>> not in title_format: {title_format} using default: {default_title_format}") title_format = default_title_format - post_format_override = util.parse("Config", "post_format_override", dynamic, parent=map_name, methods=methods, datatype="dict") if "post_format_override" in methods else {} - pre_format_override = util.parse("Config", "pre_format_override", dynamic, parent=map_name, methods=methods, datatype="dict") if "pre_format_override" in methods else {} + if "post_format_override" in methods: + methods["title_override"] = methods.pop("post_format_override") + if "pre_format_override" in methods: + methods["key_name_override"] = methods.pop("pre_format_override") + title_override = util.parse("Config", "title_override", dynamic, parent=map_name, methods=methods, datatype="dict") if "title_override" in methods else {} + key_name_override = util.parse("Config", "key_name_override", dynamic, parent=map_name, methods=methods, datatype="dict") if "key_name_override" in methods else {} test = util.parse("Config", "test", dynamic, parent=map_name, methods=methods, default=False, datatype="bool") if "test" in methods else False sync = util.parse("Config", "sync", dynamic, parent=map_name, methods=methods, default=False, datatype="bool") if "sync" in methods else False if "<<library_type>>" in title_format: @@ -403,8 +421,8 @@ class MetadataFile(DataFile): logger.debug(f"Remove Prefix: {remove_prefix}") logger.debug(f"Remove Suffix: {remove_suffix}") logger.debug(f"Title Format: {title_format}") - logger.debug(f"Pre Format Override: {pre_format_override}") - logger.debug(f"Post Format Override: {post_format_override}") + logger.debug(f"Key Name Override: {key_name_override}") + logger.debug(f"Title Override: {title_override}") logger.debug(f"Test: {test}") logger.debug(f"Sync: {sync}") logger.debug(f"Include: {include}") @@ -422,11 +440,11 @@ class MetadataFile(DataFile): for k, v in template_variables.items(): if key in v: template_call[k] = v[key] - if key in post_format_override: - collection_title = post_format_override[key] + if key in title_override: + collection_title = title_override[key] else: - if key in pre_format_override: - value = pre_format_override[key] + if key in key_name_override: + value = key_name_override[key] else: for prefix in remove_prefix: if value.startswith(prefix): diff --git a/plex_meta_manager.py b/plex_meta_manager.py index 744add9d..2b183f91 100644 --- a/plex_meta_manager.py +++ b/plex_meta_manager.py @@ -737,7 +737,7 @@ def library_operations(config, library): logger.info("") logger.info(f"Metadata Backup Path: {library.metadata_backup['path']}") logger.info("") - meta = {"metadata": {}} + meta = {} if os.path.exists(library.metadata_backup["path"]): try: meta, _, _ = yaml.util.load_yaml_guess_indent(open(library.metadata_backup["path"])) @@ -749,6 +749,8 @@ def library_operations(config, library): i += 1 os.rename(library.metadata_backup["path"], f"{filename}{i}{file_extension}") logger.error(f"Backup failed to load saving copy to {filename}{i}{file_extension}") + if "metadata" not in meta: + meta["metadata"] = {} items = library.get_all(load=True) titles = [i.title for i in items] for i, item in enumerate(items, 1):