diff --git a/VERSION b/VERSION index 952616de..d42f1ac7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.16.5-develop106 +1.16.5-develop107 diff --git a/docs/conf.py b/docs/conf.py index 608bc02b..be52383c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -128,14 +128,17 @@ html_theme_options = { ("Run Commands & Environment Variables", "home/environmental"), ("_divider", ), ("Configuration File", "config/configuration"), + ("Log Files", "home/logs"), ("Metadata Files", "metadata/metadata"), ("Overlay Files", "metadata/overlay"), ("Playlist Files", "metadata/playlist"), ("_divider", ), + ("PMM Default Config Files", "home/guides/defaults"), ("Scheduling Guide", "home/guides/scheduling"), ("Image Asset Directory Guide", "home/guides/assets"), ("Formula 1 Metadata Guide", "home/guides/formula"), ("_divider", ), + ("User Configs Repository", "https://github.com/meisnate12/Plex-Meta-Manager-Configs", True), ("Discord Server", "https://discord.gg/NfH6mGFuAB", True), ("Sponsor", "https://github.com/sponsors/meisnate12", True), ("Acknowledgements", "home/acknowledgements"), diff --git a/docs/home/guides/defaults.md b/docs/home/guides/defaults.md new file mode 100644 index 00000000..18faa86c --- /dev/null +++ b/docs/home/guides/defaults.md @@ -0,0 +1,215 @@ +# Plex Meta Manager Default Collections & Overlays + +There is a default set of Metadata and Overlay Files located in the [PMM Folder](https://github.com/meisnate12/Plex-Meta-Manager-Configs/tree/master/PMM) in the [Plex Meta Manager Configs](https://github.com/meisnate12/Plex-Meta-Manager-Configs) Repository. + +The intention of this directory is to offer easy to use and slightly customizable (using [`template_variables`](../../config/paths.md#template-variables)) Metadata and Overlay Files for a general user who wants nice collections but doesn't want to learn all of Plex Meta Manager. + +All posters defined in the Metadata Files are stored in the [Plex Meta Manager Images](https://github.com/meisnate12/Plex-Meta-Manager-Images) Repository and all Overlay images are in the [Configs](https://github.com/meisnate12/Plex-Meta-Manager-Configs) Repository at [PMM/overlays/images](https://github.com/meisnate12/Plex-Meta-Manager-Configs/tree/sohjiro/PMM/overlays/images), which allows for changes to be made in one central location that will deploy to all users of this setup when they next run PMM. + +Credits to Bullmoose20 and Yozora for helping drive this entire Default Set of Configs through the concept, design and implementation. + +Special thanks to Magic815 for the overlay image inspiration and base template. + +## Configurations + +To run a file in git you can simply add it to your `metadata_path` (For Metadata Files) or `overlay_path` (For Overlay Files) using `git` like so: + +```yaml +libraries: + Movies: + metadata_path: + - git: PMM/actor + - git: PMM/genre + overlay_path: + - remove_overlays: false + - git: PMM/overlays/imdb_top_250 + - git: PMM/overlays/ratings +``` + +## Customizing Configs + +Configs can be customized using the `template_variables` attribute when calling the file. These `template_variables` will be given to every template call in the file so they can effect how that file runs. + +```yaml +libraries: + TV Shows: + overlay_path: + - git: PMM/overlays/ratings + template_variables: + overlay_level: episode +``` + +Each file has a comment block at the top showing the available `template_variables` for each file. For example the [`PMM/genre`](https://github.com/meisnate12/Plex-Meta-Manager-Configs/blob/master/PMM/genre.yml) has this: + +```yaml +############################################################# +# Dynamic Genre Collections # +# Created by Yozora, Bullmoose20, & Sohjiro # +############################################################# +# Call this from your config.yml (Movie or Show) # +# metadata_path: # +# - git: PMM/genre # +# template_variables: # +# # Turn the separator collection on/off # +# use_separator: true # +# # Sets how the collection is sorted # +# sort_by: release.desc # +# # Sets the collection mode of the collection # +# collection_mode: # +# # Sets the value at the start of the sort title # +# collection_section: "06" # +############################################################# + +``` + +Each of these when passed will change how the collection runs slightly. +* `use_separator` Turn the separator collection on/off +* `sort_by` Sets how the collection is sorted +* `collection_mode` Sets the collection mode of the collection +* `collection_section` Sets the value at the start of the sort title + + +**In addition to the defined `template_variables` each file in the PMM Folder has access to the `radarr_add_missing` and `sonarr_add_missing` template variables and for dynamic collections most attributes can be passed as template variables** + +For example if you want yearly oscar collections that go back 10 years instead of 5 all of which gets sent to radarr use the `data` and `radarr_add_missing` template variables. + +```yaml +libraries: + Movies: + metadata_path: + - git: PMM/award/oscars + template_variables: + radarr_add_missing: true + data: + starting: current_year-10 + ending: current_year +``` + +### Example + +
+ Click to expand sample config.yml file: + +```yaml +libraries: + Movies: + metadata_path: + - git: PMM/award/bafta + - git: PMM/award/cannes + - git: PMM/award/choice + - git: PMM/award/golden + - git: PMM/award/oscars + - git: PMM/award/other + - git: PMM/award/spirit + - git: PMM/award/sundance + - git: PMM/chart/old_movie_chart + - git: PMM/actor + - git: PMM/audio_language + - git: PMM/movie/content_rating_us # Choose content_rating_uk or content_rating_us + - git: PMM/genre + - git: PMM/resolution_standards # Choose resolution_standards or resolution + - git: PMM/studio + - git: PMM/subtitle_language + - git: PMM/year + - git: PMM/movie/country_color # Choose country_color or country_white + - git: PMM/movie/decade + - git: PMM/movie/director + - git: PMM/movie/franchise + - git: PMM/movie/multi-franchise + - git: PMM/movie/producer + - git: PMM/movie/seasonal_section # Choose seasonal or seasonal_section + - git: PMM/movie/streaming + - git: PMM/movie/writer + overlay_path: + - remove_overlays: false + - git: PMM/overlays/audio_codec + - git: PMM/overlays/audio_language + - git: PMM/overlays/direct_play + - git: PMM/overlays/imdb_top_250 + - git: PMM/overlays/ratings + - git: PMM/overlays/resolution + - git: PMM/overlays/special_release + - 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 + - git: PMM/award/emmy + - git: PMM/award/golden + - git: PMM/chart/old_show_chart + - git: PMM/actor + - git: PMM/audio_language + - git: PMM/show/content_rating_us # Choose content_rating_uk or content_rating_us + - git: PMM/genre + - git: PMM/resolution_standards # Choose resolution_standards or resolution + - git: PMM/studio + - git: PMM/subtitle_language + - git: PMM/year + - git: PMM/show/country_color # Choose country_color or country_white + - git: PMM/show/decade + - git: PMM/show/network + - git: PMM/show/streaming + overlay_path: + - remove_overlays: false + - git: PMM/overlays/audio_codec + - git: PMM/overlays/audio_codec + template_variables: + overlay_level: episode + - git: PMM/overlays/audio_codec + template_variables: + overlay_level: season + - git: PMM/overlays/audio_language + - git: PMM/overlays/audio_language + template_variables: + overlay_level: episode + - git: PMM/overlays/audio_language + template_variables: + overlay_level: season + - git: PMM/overlays/direct_play + - git: PMM/overlays/direct_play + template_variables: + overlay_level: episode + - git: PMM/overlays/direct_play + template_variables: + overlay_level: season + - git: PMM/overlays/ratings + - git: PMM/overlays/ratings + template_variables: + overlay_level: episode + - git: PMM/overlays/ratings + template_variables: + overlay_level: season + - git: PMM/overlays/resolution + - git: PMM/overlays/resolution + template_variables: + overlay_level: episode + - git: PMM/overlays/resolution + template_variables: + overlay_level: season + - git: PMM/overlays/special_release + - git: PMM/overlays/special_release + template_variables: + overlay_level: episode + - git: PMM/overlays/special_release + template_variables: + overlay_level: season + - git: PMM/overlays/streaming + - git: PMM/overlays/streaming + template_variables: + overlay_level: episode + - git: PMM/overlays/streaming + template_variables: + overlay_level: season + - git: PMM/overlays/video_format + - git: PMM/overlays/video_format + template_variables: + overlay_level: episode + - git: PMM/overlays/video_format + template_variables: + overlay_level: season +playlist_files: +- git: PMM/playlist +``` +
diff --git a/docs/home/logs.md b/docs/home/logs.md new file mode 100644 index 00000000..af04e23a --- /dev/null +++ b/docs/home/logs.md @@ -0,0 +1,117 @@ +# Log files and where to find them + +Plex-Meta-Manager's log files can be found in `config/logs`: + +``` +config/logs +├── Movies +│   ├── collections +│   │   ├── Action +│   │   │   ├── collection.log +│   │   │   └── collection.log.1 +│   │   ├── Best of 2022 +│   │   │   ├── collection.log +│   │   │   └── collection.log.1 +│   │   ├── Top Rated +│   │   │   ├── collection.log +│   │   │   └── collection.log.1 +│   │   └── Trending +│   │   ├── collection.log +│   │   └── collection.log.1 +│   ├── library.log +│   └── library.log.1 +├── TV +│   ├── collections +│   │   ├── Reality +│   │   │ ├── collection.log +│   │   │ └── collection.log.1 +│   │   └── Game Shows +│   │   ├── collection.log +│   │   └── collection.log.1 +│   ├── library.log +│   └── library.log.1 +├── meta.log +├── meta.log.1 +└── playlists + ├── playlists.log + └── playlists.log.1 +``` + +You will find a `meta.log`, which the the full log of the entire run. + +The subfolders provide more limited logs at the library, collection, and playlist levels. + +As new log files are created, the old ones get a numeric suffix added: `meta.log.1`. The most recent is always the one without a number at the end. + +These files will contain a great deal of detail about what exactly is happening and why. Generally speaking, if you're having a problem with PMM the answer will be found here. These logs can of course be quite technical, but often the error can be relatively clear: + + +Something's missing from the format of the file: +``` +| Loading Metadata File: config/TV Shows.yml | +| | +| YAML Error: metadata, collections, or dynamic_collections attribute is required | +``` + +The problem in that case was: + +```yaml +templates: + Collection: + cache_builders: 30 + sync_mode: sync + sort_title: ZZZ-<>-<> + +collections: <<< THIS LINE WAS MISSING + Cached for 30 Days: + template: {name: Collection, source: Looper} + summary: "" + trakt_list: + - https://trakt.tv/users/kesleyalfa/lists/year-2011 +``` + + +YAML doesn't allow duplicate keys: +``` +| Loading Metadata File: config/Anime.yml | +| | +| YAML Error: while constructing a mapping +| in "", line 27, column 5: +| mal_favorite: 50 +| ^ (line: 27) +| found duplicate key "collection_order" with value "custom" (original value: "custom") +| in "", line 32, column 5: +| collection_order: custom +| ^ (line: 32) +``` + +The problem there was something like this: +```yaml +templates: + Collection: + cache_builders: 30 + sync_mode: sync + sort_title: ZZZ-<>-<> + +collections: <<< THIS LINE WAS MISSING + Cached for 30 Days: + template: {name: Collection, source: Looper} + collection_order: custom <<<< THIS KEY + summary: "" + collection_order: custom <<<< DUPLICATED HERE + trakt_list: + - https://trakt.tv/users/kesleyalfa/lists/year-2011 +``` + +File isn't where PMM expects it: +``` +| Loading Metadata File: config/Movies.yml | +| YAML Error: File Error: File does not exist /Users/Lucky/Plex-Meta-Manager/config/Movies.yml | +``` + +## Providing Log Files + +You can drag-and-drop your meta.log file directly into Discord, you do not need to upload it to a third-party site unless it exceeds the 50mb size limit. + +Please DO NOT manually extract, copy and paste text from your log files directly into Discord as the formatting can be difficult to read and can often redact parts of the log file that are important for full context. + diff --git a/docs/metadata/builders/letterboxd.md b/docs/metadata/builders/letterboxd.md index fd3bc439..063d0725 100644 --- a/docs/metadata/builders/letterboxd.md +++ b/docs/metadata/builders/letterboxd.md @@ -11,11 +11,13 @@ No configuration is required for these builders. ## Letterboxd List -Finds every movie in the Letterboxd List. +Finds every movie in the Letterboxd List or [Letterboxd Films Search](https://letterboxd.com/films/). -The expected input is a Letterboxd List URL. Multiple values are supported as either a list or a comma-separated string. +The expected input is a Letterboxd List URL or Letterboxd Film Search URL. Multiple values are supported as either a list or a comma-separated string. -The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order. +The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order. + +Using the `limit` filter attribute is recommended when using a Letterboxd Film Search as the number of results returned could be very large. ```yaml collections: @@ -36,10 +38,11 @@ collections: sync_mode: sync ``` -You can add 3 different filters directly to this builder. +You can add different filters directly to this builder. | Filter Attribute | Description | |:-----------------|:---------------------------------------------------------------------------------------------------| +| `limit` | **Description:** Max number of items per returned
**Values:** number greater than `1` | | `rating` | **Description:** Search for the specified rating range
**Values:** range of int i.e. `80-100` | | `year` | **Description:** Search for the specified year range
**Values:** range of int i.e. `1990-1999` | | `note` | **Description:** Search for the specified value in the note
**Values:** Any String | diff --git a/docs/metadata/dynamic.md b/docs/metadata/dynamic.md index c815612c..23289e68 100644 --- a/docs/metadata/dynamic.md +++ b/docs/metadata/dynamic.md @@ -898,7 +898,7 @@ default_template: * Create dynamic collections based on each genre found in the library (TV and Movies) * Amend the template to increase the limit from 50 to 100 * Exclude the "Talk Show" genre -* Name the collection Top [Genre] Movies or Top [Genre] Shows +* Name the collection "Top [Genre] Movies" or "Top [Genre] Shows" ```yaml templates: @@ -1024,7 +1024,7 @@ default_template: * Create dynamic collections based on each year found in the library (TV and Movies) * Use the `include` attribute to only show collections for years "2020", "2021" and "2022" -* Name the collection "Best of (year)" +* Name the collection "Best of [Year]" ```yaml dynamic_collections: @@ -1082,7 +1082,7 @@ default_template: ### Example: * Create a collection for each decade found in the library (TV and Movies) -* Name the collection Top [Decade] Movies +* Name the collection "Top [Decade] Movies" * Rename the `2020` collection name to "Top 2020 Movies (so far)" ```yaml @@ -1139,7 +1139,7 @@ default_template: #### Example: * Create a collection for the top movies from each country found in the library -* Name the collection Top [Country] Cinema +* Name the collection "Top [Country] 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 @@ -1483,7 +1483,7 @@ default_template: #### Example: * Create a collection for the top 100 items for each mood found in the Music library -* Name the collection Top [Mood] Tracks +* Name the collection "Top [Mood] Tracks" ```yaml templates: @@ -1546,7 +1546,7 @@ default_template: #### Example: * Create a collection for the top 10 albums for each style found in the Music library -* Name the collection Top [Style] Albums +* Name the collection "Top [Style] Albums" ```yaml templates: @@ -1621,14 +1621,39 @@ Creates a collection for each number defined. -### List -Creates a collection for each item in the list defined . +#### Example: + +* Create a collection for the Oscar Winner by Year for the last 5 years +* Name the collection "Oscars Winners [Number]" + +```yaml +templates: + Oscars: + summary: Academy Awards (Oscars) Winners for <> + imdb_list: https://www.imdb.com/search/title/?release_date=<>-01-01,<>-12-31&groups=oscar_winner&sort=moviemeter,asc + sync_mode: sync + collection_order: custom +dynamic_collections: + Oscars Winners Awards: + type: number + sync: true + data: + starting: current_year-5 + ending: current_year + title_format: Oscars Winners <> + template: + - Oscars +``` + +### Custom + +Creates a collection for each custom `key: key_name` pair defined. - + @@ -1636,11 +1661,11 @@ Creates a collection for each item in the list defined . - + - + @@ -1652,6 +1677,44 @@ Creates a collection for each item in the list defined .
type Optionlistcustom
data Values
KeysStringkey
Key NamesStringkey_name
Default title_format
+#### Example: + +* Create a collection for the various Streaming Services +* Name the collection "[Key Name] Movies" + +```yaml + + +templates: + streaming: + cache_builders: 1 + smart_label: release.desc + sync_mode: sync + mdblist_list: https://mdblist.com/lists/plexmetamanager/<>-movies + url_poster: https://raw.githubusercontent.com/meisnate12/Plex-Meta-Manager-Images/master/streaming/<>.jpg + +dynamic_collections: + Streaming: + type: custom + data: + all-4: All 4 + appletv: Apple TV+ + bet: BET+ + britbox: BritBox + disney: Disney+ + hbo-max: HBO Max + hulu: Hulu + netflix: Netflix + now: NOW + paramount: Paramount+ + peacock: Peacock + amazon-prime-video: Prime Video + title_format: <> Movies + template: + - streaming + - shared +``` + ## Exclude Exclude this list of `keys` from being created into collections. diff --git a/modules/meta.py b/modules/meta.py index 8f1892ee..4b429337 100644 --- a/modules/meta.py +++ b/modules/meta.py @@ -6,7 +6,7 @@ from plexapi.exceptions import NotFound, BadRequest logger = util.logger -all_auto = ["genre", "number", "list"] +all_auto = ["genre", "number", "custom"] ms_auto = [ "actor", "year", "content_rating", "original_language", "tmdb_popular_people", "trakt_user_lists", "studio", "trakt_liked_lists", "trakt_people_list", "subtitle_language", "audio_language", "resolution", "decade" @@ -164,6 +164,9 @@ class DataFile: if "optional" in template: if template["optional"]: for op in util.get_list(template["optional"]): + for k, v in variables.items(): + if f"<<{k}>>" in op: + op = op.replace(f"<<{k}>>", str(v)) if op not in default: optional.append(str(op)) optional.append(f"{op}_encoded") @@ -211,19 +214,26 @@ class DataFile: 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 - for variable, variable_data in variables.items(): - if (variable == "collection_name" or variable == "playlist_name") and _method in ["radarr_tag", "item_radarr_tag", "sonarr_tag", "item_sonarr_tag"]: - final_data = scan_text(final_data, variable, variable_data.replace(",", "")) - elif variable != "name": - final_data = scan_text(final_data, variable, variable_data) + clean = False + while not clean: + clean = True + 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(",", "")) + elif variable != "name": + var_data = scan_text(final_data, variable, variable_data) + if var_data: + final_data = var_data + clean = False for dm, dd in default.items(): - final_data = scan_text(final_data, dm, dd) + default_data = scan_text(final_data, dm, dd) + if default_data: + final_data = default_data return final_data for method_name, attr_data in template.items(): @@ -469,13 +479,13 @@ class MetadataFile(DataFile): if str(current) not in exclude and current not in exclude: auto_list[str(current)] = str(current) current += increment - elif auto_type == "list": + elif auto_type == "custom": if "data" not in methods: raise Failed(f"Config Error: {map_name} data attribute not found") - for list_item in util.parse("Config", "data", dynamic, parent=map_name, methods=methods, datatype="strlist"): - all_keys.append(list_item) - if list_item not in exclude: - auto_list[list_item] = list_item + for k, v in util.parse("Config", "data", dynamic, parent=map_name, methods=methods, datatype="strdict").items(): + all_keys.append(k) + if k not in exclude and v not in exclude: + auto_list[k] = v elif auto_type == "trakt_user_lists": dynamic_data = util.parse("Config", "data", dynamic, parent=map_name, methods=methods, datatype="list") for option in dynamic_data: