diff --git a/VERSION b/VERSION
index aeef2a889..092afa15d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.16.5-develop118
+1.17.0
diff --git a/config/config.yml.template b/config/config.yml.template
index 1ab69782c..c3b031a66 100644
--- a/config/config.yml.template
+++ b/config/config.yml.template
@@ -5,24 +5,33 @@ libraries: # This is called out once within
metadata_path:
- file: config/Movies.yml # This is a local file on the system
- folder: config/Movies/ # This is a local directory on the system
- - git: meisnate12/MovieCharts # This is a file within the GitHub Repository
+ - git: PMM/chart/basic # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
+ - git: PMM/chart/imdb # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
overlay_path:
- remove_overlays: false # Set this to true to remove all overlays
- file: config/Overlays.yml # This is a local file on the system
+ - git: PMM/overlays/imdb_top_250 # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
TV Shows:
metadata_path:
- file: config/TVShows.yml
- folder: config/TV Shows/
- - git: meisnate12/ShowCharts # This points to the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
+ - git: PMM/chart/basic # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
+ - git: PMM/chart/imdb # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
+ overlay_path:
+ - remove_overlays: false # Set this to true to remove all overlays
+ - file: config/Overlays.yml # This is a local file on the system
+ - git: PMM/overlays/imdb_top_250 # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
Anime:
metadata_path:
- file: config/Anime.yml
+ - git: PMM/chart/basic # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
+ - git: PMM/chart/anilist # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
Music:
metadata_path:
- file: config/Music.yml
playlist_files:
- file: config/playlists.yml
- - git: meisnate12/Playlists
+ - git: PMM/playlist # This is a file within the https://github.com/meisnate12/Plex-Meta-Manager-Configs Repository
settings:
cache: true
cache_expiration: 60
diff --git a/docs/conf.py b/docs/conf.py
index eb7ce5b6a..bca6f40a1 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -130,7 +130,7 @@
("Overlay Files", "metadata/overlay"),
("Playlist Files", "metadata/playlist"),
("_divider", ),
- ("Default Configs and Overlays", "home/guides/defaults"),
+ ("Default Metadata & Overlays Files", "home/guides/defaults"),
("Scheduling Guide", "home/guides/scheduling"),
("Image Asset Directory Guide", "home/guides/assets"),
("Formula 1 Metadata Guide", "home/guides/formula"),
diff --git a/docs/home/guides/defaults.md b/docs/home/guides/defaults.md
index 9acd54205..bf6b32f51 100644
--- a/docs/home/guides/defaults.md
+++ b/docs/home/guides/defaults.md
@@ -1,4 +1,4 @@
-# Default Collections & Overlays
+# Default Metadata & Overlays Files
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.
@@ -143,7 +143,14 @@ libraries:
- git: PMM/award/other
- git: PMM/award/spirit
- git: PMM/award/sundance
- - git: PMM/chart/old_movie_chart
+ - git: PMM/chart/anilist
+ - git: PMM/chart/basic
+ - git: PMM/chart/imdb
+ - git: PMM/chart/myanimelist
+ - git: PMM/chart/other
+ - git: PMM/chart/tautulli
+ - git: PMM/chart/tmdb
+ - git: PMM/chart/trakt
- git: PMM/actor
- git: PMM/audio_language
- git: PMM/movie/content_rating_us # Choose content_rating_uk or content_rating_us
@@ -156,7 +163,7 @@ libraries:
- git: PMM/movie/decade
- git: PMM/movie/director
- git: PMM/movie/franchise
- - git: PMM/movie/multi-franchise
+ - git: PMM/movie/universe
- git: PMM/movie/producer
- git: PMM/movie/seasonal
- git: PMM/movie/streaming
@@ -177,7 +184,14 @@ libraries:
- git: PMM/award/choice
- git: PMM/award/golden
- git: PMM/award/emmy
- - git: PMM/chart/old_show_chart
+ - git: PMM/chart/anilist
+ - git: PMM/chart/basic
+ - git: PMM/chart/imdb
+ - git: PMM/chart/myanimelist
+ - git: PMM/chart/other
+ - git: PMM/chart/tautulli
+ - git: PMM/chart/tmdb
+ - git: PMM/chart/trakt
- git: PMM/actor
- git: PMM/audio_language
- git: PMM/show/content_rating_us # Choose content_rating_uk or content_rating_us
@@ -192,7 +206,7 @@ libraries:
- git: PMM/show/streaming
overlay_path:
- remove_overlays: false
- - git: PMM/overlays/audio_codec
+ - git: PMM/overlays/audio_codec
- git: PMM/overlays/audio_codec
template_variables:
overlay_level: episode
diff --git a/docs/metadata/details/metadata.md b/docs/metadata/details/metadata.md
index 4ad20b8ac..c246e84e6 100644
--- a/docs/metadata/details/metadata.md
+++ b/docs/metadata/details/metadata.md
@@ -45,6 +45,7 @@ None of these details work with Playlists.
| `item_lock_poster` | **Description:** Locks/Unlocks the poster of every movie/show in the collection
**Default:** `None`
**Values:**
|
| `item_lock_background` | **Description:** Locks/Unlocks the background of every movie/show in the collection
**Default:** `None`
**Values:** |
| `item_lock_title` | **Description:** Locks/Unlocks the title of every movie/show in the collection
**Default:** `None`
**Values:** |
+| `item_assets` | **Description:** Checks your assets folders for assets of every movie/show in the collection
**Default:** `false`
**Values:** `true` or `false` |
| `item_refresh` | **Description:** Refreshes the metadata of every movie/show in the collection
**Default:** `false`
**Values:** `true` or `false` |
| `item_refresh_delay` | **Description:** Amount of time to wait between each `item_refresh` of every movie/show in the collection
**Default:** `0`
**Values:** Number greater than `0` |
| `item_tmdb_season_titles` | **Description:** Changes the season titles of every show in the collection to match TMDb
**Default:** `false`
**Values:** `true` or `false` |
diff --git a/docs/metadata/overlay.md b/docs/metadata/overlay.md
index ac0e06b84..61ae95428 100644
--- a/docs/metadata/overlay.md
+++ b/docs/metadata/overlay.md
@@ -145,9 +145,11 @@ You can control the backdrop of the text using the various `back_*` attributes.
The `horizontal_offset` and `vertical_offset` overlay attributes are required when using Text Overlays.
-You can add an items rating number (`8.7`) to the image by using `text(audience_rating)`, `text(critic_rating)`, or `text(user_rating)`
+You can add an items rating number (`8.7`, `9.0`) to the image by using `text(audience_rating)`, `text(critic_rating)`, or `text(user_rating)`
-You can add an items rating percentage (`87%`) to the image by using `text(audience_rating%)`, `text(critic_rating%)`, or `text(user_rating%)`
+You can add an items rating number removing `.0` as needed (`8.7`, `9`) to the image by using `text(audience_rating#)`, `text(critic_rating#)`, or `text(user_rating#)`
+
+You can add an items rating percentage (`87%`, `90%`) to the image by using `text(audience_rating%)`, `text(critic_rating%)`, or `text(user_rating%)`
You can use the `mass_audience_rating_update` or `mass_critic_rating_update` [Library Operation](../config/operations) to update your plex ratings to various services like `tmdb`, `imdb`, `mdb`, `metacritic`, `letterboxd` and many more.
diff --git a/modules/builder.py b/modules/builder.py
index 4ee192bd5..e7025aee2 100644
--- a/modules/builder.py
+++ b/modules/builder.py
@@ -49,8 +49,8 @@
collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \
poster_details + background_details + summary_details + string_details
item_false_details = ["item_lock_background", "item_lock_poster", "item_lock_title"]
-item_bool_details = ["item_tmdb_season_titles", "revert_overlay", "item_refresh"] + item_false_details
-item_details = ["non_item_remove_label", "item_label", "item_radarr_tag", "item_sonarr_tag", "item_overlay", "item_refresh_delay"] + item_bool_details + list(plex.item_advance_keys.keys())
+item_bool_details = ["item_tmdb_season_titles", "revert_overlay", "item_assets", "item_refresh"] + item_false_details
+item_details = ["non_item_remove_label", "item_label", "item_radarr_tag", "item_sonarr_tag", "item_refresh_delay"] + item_bool_details + list(plex.item_advance_keys.keys())
none_details = ["label.sync", "item_label.sync", "radarr_taglist", "sonarr_taglist"]
radarr_details = [
"radarr_add_missing", "radarr_add_existing", "radarr_upgrade_existing", "radarr_folder", "radarr_monitor",
@@ -160,7 +160,7 @@
] + custom_sort_builders + summary_details + poster_details + radarr_details + sonarr_details
music_attributes = [
"non_item_remove_label", "item_label", "collection_filtering", "item_lock_background", "item_lock_poster", "item_lock_title",
- "item_refresh", "item_refresh_delay", "plex_search", "plex_all", "filters"
+ "item_assets", "item_refresh", "item_refresh_delay", "plex_search", "plex_all", "filters"
] + details + summary_details + poster_details + background_details
class CollectionBuilder:
@@ -906,38 +906,6 @@ def _item_details(self, method_name, method_data, method_mod, method_final, meth
raise Failed(f"{self.Type} Error: Cannot use {method_name} and {method_name}.remove together")
self.item_details[method_name] = util.get_list(method_data, lower=True)
self.item_details["apply_tags"] = method_mod[1:] if method_mod else ""
- elif method_name == "item_overlay":
- if isinstance(method_data, dict):
- if "name" not in method_data or not method_data["name"]:
- raise Failed(f"{self.Type} Error: item_overlay must have the name attribute")
- if "git" in method_data and method_data["git"]:
- url = f"https://github.com/meisnate12/Plex-Meta-Manager-Configs/blob/master/{method_data['git']}.png"
- elif "url" in method_data and method_data["url"]:
- url = method_data["url"]
- else:
- raise Failed(f"{self.Type} Error: item_overlay must have either the git or url attribute")
- name = method_data["name"]
- response = self.config.get(url)
- if response.status_code >= 400:
- raise Failed(f"{self.Type} Error: Overlay Image not found at: {url}")
- overlay_dir = os.path.join(self.config.default_dir, "overlays", name)
- if not os.path.exists(overlay_dir) or not os.path.isdir(overlay_dir):
- os.makedirs(overlay_dir, exist_ok=False)
- logger.info(f"Creating Overlay Folder found at: {overlay_dir}")
- overlay = os.path.join(overlay_dir, "overlay.png")
- with open(overlay, "wb") as handler:
- handler.write(response.content)
- while util.is_locked(overlay):
- time.sleep(1)
- else:
- overlay = os.path.join(self.config.default_dir, "overlays", method_data, "overlay.png")
- name = method_data
- if not os.path.exists(overlay):
- raise Failed(f"{self.Type} Error: {name} overlay image not found at {overlay}")
- if name in self.library.overlays_old:
- raise Failed("Each Overlay can only be used once per Library")
- self.library.overlays_old.append(name)
- self.item_details[method_name] = name
elif method_name == "item_refresh_delay":
self.item_details[method_name] = util.parse(self.Type, method_name, method_data, datatype="int", default=0, minimum=0)
elif method_name in item_bool_details:
@@ -2327,6 +2295,8 @@ def update_item_details(self):
tmdb_paths = []
tvdb_paths = []
for item in self.items:
+ if "item_assets" in self.item_details and self.library.asset_directory and "Overlay" not in [la.tag for la in item.labels]:
+ self.library.find_and_upload_assets(item)
self.library.edit_tags("label", item, add_tags=add_tags, remove_tags=remove_tags, sync_tags=sync_tags)
path = os.path.dirname(str(item.locations[0])) if self.library.is_movie else str(item.locations[0])
if self.library.Radarr and item.ratingKey in self.library.movie_rating_key_map:
diff --git a/modules/operations.py b/modules/operations.py
index 2df6c109c..1ce11e686 100644
--- a/modules/operations.py
+++ b/modules/operations.py
@@ -82,52 +82,7 @@ def run_operations(self):
current_labels = [la.tag for la in item.labels] if self.library.assets_for_all or self.library.mass_imdb_parental_labels else []
if self.library.assets_for_all and self.library.asset_directory and "Overlay" not in current_labels:
- try:
- poster, background, item_dir, name = self.library.find_item_assets(item)
- if poster or background:
- self.library.upload_images(item, poster=poster, background=background)
- elif self.library.show_missing_assets:
- logger.warning(f"Asset Warning: No poster or background found in the assets folder '{item_dir}'")
-
- if isinstance(item, Show):
- missing_seasons = ""
- missing_episodes = ""
- found_season = False
- found_episode = False
- for season in self.library.query(item.seasons):
- season_poster, season_background, _, _ = self.library.find_item_assets(season, item_asset_directory=item_dir)
- if season_poster:
- found_season = True
- elif self.library.show_missing_season_assets and season.seasonNumber > 0:
- missing_seasons += f"\nMissing Season {season.seasonNumber} Poster"
- if season_poster or season_background:
- self.library.upload_images(season, poster=season_poster, background=season_background)
- for episode in self.library.query(season.episodes):
- if episode.seasonEpisode:
- episode_poster, episode_background, _, _ = self.library.find_item_assets(episode, item_asset_directory=item_dir)
- if episode_poster or episode_background:
- found_episode = True
- self.library.upload_images(episode, poster=episode_poster, background=episode_background)
- elif self.library.show_missing_episode_assets:
- missing_episodes += f"\nMissing {episode.seasonEpisode.upper()} Title Card"
- if (found_season and missing_seasons) or (found_episode and missing_episodes):
- logger.info(f"Missing Posters for {item.title}{missing_seasons}{missing_episodes}")
- if isinstance(item, Artist):
- missing_assets = ""
- found_album = False
- for album in self.library.query(item.albums):
- album_poster, album_background, _, _ = self.library.find_item_assets(album, item_asset_directory=item_dir)
- if album_poster or album_background:
- found_album = True
- elif self.library.show_missing_season_assets:
- missing_assets += f"\nMissing Album {album.title} Poster"
- if album_poster or album_background:
- self.library.upload_images(album, poster=album_poster, background=album_background)
- if self.library.show_missing_season_assets and found_album and missing_assets:
- logger.info(f"Missing Album Posters for {item.title}{missing_assets}")
- except Failed as e:
- if self.library.show_missing_assets:
- logger.warning(e)
+ self.library.find_and_upload_assets(item)
tmdb_id, tvdb_id, imdb_id = self.library.get_ids(item)
diff --git a/modules/overlays.py b/modules/overlays.py
index d921c6cbd..35c1ac28a 100644
--- a/modules/overlays.py
+++ b/modules/overlays.py
@@ -179,9 +179,10 @@ def run_overlays(self):
for over_name in text_names:
overlay = properties[over_name]
text = over_name[5:-1]
- if text in [f"{a}{s}" for a in ["audience_rating", "critic_rating", "user_rating"] for s in ["", "%"]]:
+ if text in [f"{a}{s}" for a in ["audience_rating", "critic_rating", "user_rating"] for s in ["", "%", "#"]]:
per = text.endswith("%")
- rating_type = text[:-1] if per else text
+ flat = text.endswith("#")
+ rating_type = text[:-1] if per or flat else text
actual = plex.attribute_translation[rating_type]
if not hasattr(item, actual) or getattr(item, actual) is None:
logger.warning(f"Overlay Warning: No {rating_type} found")
@@ -191,6 +192,8 @@ def run_overlays(self):
self.config.Cache.update_overlay_ratings(item.ratingKey, rating_type, text)
if per:
text = f"{int(text * 10)}%"
+ if flat and str(text).endswith(".0"):
+ text = str(text)[:-2]
overlay_image = overlay.get_text_overlay(text, image_width, image_height)
else:
overlay_image = overlay.landscape if isinstance(item, Episode) else overlay.image
diff --git a/modules/plex.py b/modules/plex.py
index 11c032914..12d17593f 100644
--- a/modules/plex.py
+++ b/modules/plex.py
@@ -913,6 +913,54 @@ def item_images(self, item, group, alias, asset_location=None, title=None, image
self.upload_images(item, poster=poster, background=background)
return asset_location
+ def find_and_upload_assets(self, item):
+ try:
+ poster, background, item_dir, name = self.find_item_assets(item)
+ if poster or background:
+ self.upload_images(item, poster=poster, background=background)
+ elif self.show_missing_assets:
+ logger.warning(f"Asset Warning: No poster or background found in the assets folder '{item_dir}'")
+
+ if isinstance(item, Show):
+ missing_seasons = ""
+ missing_episodes = ""
+ found_season = False
+ found_episode = False
+ for season in self.query(item.seasons):
+ season_poster, season_background, _, _ = self.find_item_assets(season, item_asset_directory=item_dir)
+ if season_poster:
+ found_season = True
+ elif self.show_missing_season_assets and season.seasonNumber > 0:
+ missing_seasons += f"\nMissing Season {season.seasonNumber} Poster"
+ if season_poster or season_background:
+ self.upload_images(season, poster=season_poster, background=season_background)
+ for episode in self.query(season.episodes):
+ if episode.seasonEpisode:
+ episode_poster, episode_background, _, _ = self.find_item_assets(episode, item_asset_directory=item_dir)
+ if episode_poster or episode_background:
+ found_episode = True
+ self.upload_images(episode, poster=episode_poster, background=episode_background)
+ elif self.show_missing_episode_assets:
+ missing_episodes += f"\nMissing {episode.seasonEpisode.upper()} Title Card"
+ if (found_season and missing_seasons) or (found_episode and missing_episodes):
+ logger.info(f"Missing Posters for {item.title}{missing_seasons}{missing_episodes}")
+ if isinstance(item, Artist):
+ missing_assets = ""
+ found_album = False
+ for album in self.query(item.albums):
+ album_poster, album_background, _, _ = self.find_item_assets(album, item_asset_directory=item_dir)
+ if album_poster or album_background:
+ found_album = True
+ elif self.show_missing_season_assets:
+ missing_assets += f"\nMissing Album {album.title} Poster"
+ if album_poster or album_background:
+ self.upload_images(album, poster=album_poster, background=album_background)
+ if self.show_missing_season_assets and found_album and missing_assets:
+ logger.info(f"Missing Album Posters for {item.title}{missing_assets}")
+ except Failed as e:
+ if self.show_missing_assets:
+ logger.warning(e)
+
def find_item_assets(self, item, item_asset_directory=None, asset_directory=None):
poster = None
background = None
diff --git a/modules/trakt.py b/modules/trakt.py
index e21085b37..bb8711550 100644
--- a/modules/trakt.py
+++ b/modules/trakt.py
@@ -218,6 +218,7 @@ def _request(self, url, params=None, json=None):
raise Failed(f"({response.status_code}) {response.reason}")
json_data = response.json()
if self.config.trace_mode:
+ logger.debug(f"Headers: {response.headers}")
logger.debug(f"Response: {json_data}")
if isinstance(json_data, dict):
return json_data