pull/933/head v1.17.0
meisnate12 3 years ago
parent e16ed9fcf8
commit 4e4c173e43

@ -1 +1 @@
1.16.5-develop118 1.17.0

@ -5,24 +5,33 @@ libraries: # This is called out once within
metadata_path: metadata_path:
- file: config/Movies.yml # This is a local file on the system - file: config/Movies.yml # This is a local file on the system
- folder: config/Movies/ # This is a local directory 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: overlay_path:
- remove_overlays: false # Set this to true to remove all overlays - remove_overlays: false # Set this to true to remove all overlays
- file: config/Overlays.yml # This is a local file on the system - 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: TV Shows:
metadata_path: metadata_path:
- file: config/TVShows.yml - file: config/TVShows.yml
- folder: config/TV Shows/ - 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: Anime:
metadata_path: metadata_path:
- file: config/Anime.yml - 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: Music:
metadata_path: metadata_path:
- file: config/Music.yml - file: config/Music.yml
playlist_files: playlist_files:
- file: config/playlists.yml - 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: settings:
cache: true cache: true
cache_expiration: 60 cache_expiration: 60

@ -130,7 +130,7 @@ html_theme_options = {
("Overlay Files", "metadata/overlay"), ("Overlay Files", "metadata/overlay"),
("Playlist Files", "metadata/playlist"), ("Playlist Files", "metadata/playlist"),
("_divider", ), ("_divider", ),
("Default Configs and Overlays", "home/guides/defaults"), ("Default Metadata & Overlays Files", "home/guides/defaults"),
("Scheduling Guide", "home/guides/scheduling"), ("Scheduling Guide", "home/guides/scheduling"),
("Image Asset Directory Guide", "home/guides/assets"), ("Image Asset Directory Guide", "home/guides/assets"),
("Formula 1 Metadata Guide", "home/guides/formula"), ("Formula 1 Metadata Guide", "home/guides/formula"),

@ -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. 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/other
- git: PMM/award/spirit - git: PMM/award/spirit
- git: PMM/award/sundance - 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/actor
- git: PMM/audio_language - git: PMM/audio_language
- git: PMM/movie/content_rating_us # Choose content_rating_uk or content_rating_us - 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/decade
- git: PMM/movie/director - git: PMM/movie/director
- git: PMM/movie/franchise - git: PMM/movie/franchise
- git: PMM/movie/multi-franchise - git: PMM/movie/universe
- git: PMM/movie/producer - git: PMM/movie/producer
- git: PMM/movie/seasonal - git: PMM/movie/seasonal
- git: PMM/movie/streaming - git: PMM/movie/streaming
@ -177,7 +184,14 @@ libraries:
- git: PMM/award/choice - git: PMM/award/choice
- git: PMM/award/golden - git: PMM/award/golden
- git: PMM/award/emmy - 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/actor
- git: PMM/audio_language - git: PMM/audio_language
- git: PMM/show/content_rating_us # Choose content_rating_uk or content_rating_us - git: PMM/show/content_rating_us # Choose content_rating_uk or content_rating_us

@ -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<br>**Default:** `None`<br>**Values:**<table class="clearTable"><tr><td>`true`</td><td>Lock</td></tr><tr><td>`false`</td><td>Unlock</td></tr></table> | | `item_lock_poster` | **Description:** Locks/Unlocks the poster of every movie/show in the collection<br>**Default:** `None`<br>**Values:**<table class="clearTable"><tr><td>`true`</td><td>Lock</td></tr><tr><td>`false`</td><td>Unlock</td></tr></table> |
| `item_lock_background` | **Description:** Locks/Unlocks the background of every movie/show in the collection<br>**Default:** `None`<br>**Values:**<table class="clearTable"><tr><td>`true`</td><td>Lock</td></tr><tr><td>`false`</td><td>Unlock</td></tr></table> | | `item_lock_background` | **Description:** Locks/Unlocks the background of every movie/show in the collection<br>**Default:** `None`<br>**Values:**<table class="clearTable"><tr><td>`true`</td><td>Lock</td></tr><tr><td>`false`</td><td>Unlock</td></tr></table> |
| `item_lock_title` | **Description:** Locks/Unlocks the title of every movie/show in the collection<br>**Default:** `None`<br>**Values:**<table class="clearTable"><tr><td>`true`</td><td>Lock</td></tr><tr><td>`false`</td><td>Unlock</td></tr></table> | | `item_lock_title` | **Description:** Locks/Unlocks the title of every movie/show in the collection<br>**Default:** `None`<br>**Values:**<table class="clearTable"><tr><td>`true`</td><td>Lock</td></tr><tr><td>`false`</td><td>Unlock</td></tr></table> |
| `item_assets` | **Description:** Checks your assets folders for assets of every movie/show in the collection<br>**Default:** `false`<br>**Values:** `true` or `false` |
| `item_refresh` | **Description:** Refreshes the metadata of every movie/show in the collection<br>**Default:** `false`<br>**Values:** `true` or `false` | | `item_refresh` | **Description:** Refreshes the metadata of every movie/show in the collection<br>**Default:** `false`<br>**Values:** `true` or `false` |
| `item_refresh_delay` | **Description:** Amount of time to wait between each `item_refresh` of every movie/show in the collection<br>**Default:** `0`<br>**Values:** Number greater than `0` | | `item_refresh_delay` | **Description:** Amount of time to wait between each `item_refresh` of every movie/show in the collection<br>**Default:** `0`<br>**Values:** Number greater than `0` |
| `item_tmdb_season_titles` | **Description:** Changes the season titles of every show in the collection to match TMDb<br>**Default:** `false`<br>**Values:** `true` or `false` | | `item_tmdb_season_titles` | **Description:** Changes the season titles of every show in the collection to match TMDb<br>**Default:** `false`<br>**Values:** `true` or `false` |

@ -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. 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. 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.

@ -49,8 +49,8 @@ details = [
collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \ collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \
poster_details + background_details + summary_details + string_details poster_details + background_details + summary_details + string_details
item_false_details = ["item_lock_background", "item_lock_poster", "item_lock_title"] 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_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_overlay", "item_refresh_delay"] + item_bool_details + list(plex.item_advance_keys.keys()) 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"] none_details = ["label.sync", "item_label.sync", "radarr_taglist", "sonarr_taglist"]
radarr_details = [ radarr_details = [
"radarr_add_missing", "radarr_add_existing", "radarr_upgrade_existing", "radarr_folder", "radarr_monitor", "radarr_add_missing", "radarr_add_existing", "radarr_upgrade_existing", "radarr_folder", "radarr_monitor",
@ -160,7 +160,7 @@ playlist_attributes = [
] + custom_sort_builders + summary_details + poster_details + radarr_details + sonarr_details ] + custom_sort_builders + summary_details + poster_details + radarr_details + sonarr_details
music_attributes = [ music_attributes = [
"non_item_remove_label", "item_label", "collection_filtering", "item_lock_background", "item_lock_poster", "item_lock_title", "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 ] + details + summary_details + poster_details + background_details
class CollectionBuilder: class CollectionBuilder:
@ -906,38 +906,6 @@ class CollectionBuilder:
raise Failed(f"{self.Type} Error: Cannot use {method_name} and {method_name}.remove together") 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[method_name] = util.get_list(method_data, lower=True)
self.item_details["apply_tags"] = method_mod[1:] if method_mod else "" 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": 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) 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: elif method_name in item_bool_details:
@ -2327,6 +2295,8 @@ class CollectionBuilder:
tmdb_paths = [] tmdb_paths = []
tvdb_paths = [] tvdb_paths = []
for item in self.items: 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) 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]) 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: if self.library.Radarr and item.ratingKey in self.library.movie_rating_key_map:

@ -82,52 +82,7 @@ class Operations:
current_labels = [la.tag for la in item.labels] if self.library.assets_for_all or self.library.mass_imdb_parental_labels else [] 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: if self.library.assets_for_all and self.library.asset_directory and "Overlay" not in current_labels:
try: self.library.find_and_upload_assets(item)
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)
tmdb_id, tvdb_id, imdb_id = self.library.get_ids(item) tmdb_id, tvdb_id, imdb_id = self.library.get_ids(item)

@ -179,9 +179,10 @@ class Overlays:
for over_name in text_names: for over_name in text_names:
overlay = properties[over_name] overlay = properties[over_name]
text = over_name[5:-1] 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("%") 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] actual = plex.attribute_translation[rating_type]
if not hasattr(item, actual) or getattr(item, actual) is None: if not hasattr(item, actual) or getattr(item, actual) is None:
logger.warning(f"Overlay Warning: No {rating_type} found") logger.warning(f"Overlay Warning: No {rating_type} found")
@ -191,6 +192,8 @@ class Overlays:
self.config.Cache.update_overlay_ratings(item.ratingKey, rating_type, text) self.config.Cache.update_overlay_ratings(item.ratingKey, rating_type, text)
if per: if per:
text = f"{int(text * 10)}%" 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) overlay_image = overlay.get_text_overlay(text, image_width, image_height)
else: else:
overlay_image = overlay.landscape if isinstance(item, Episode) else overlay.image overlay_image = overlay.landscape if isinstance(item, Episode) else overlay.image

@ -913,6 +913,54 @@ class Plex(Library):
self.upload_images(item, poster=poster, background=background) self.upload_images(item, poster=poster, background=background)
return asset_location 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): def find_item_assets(self, item, item_asset_directory=None, asset_directory=None):
poster = None poster = None
background = None background = None

@ -218,6 +218,7 @@ class Trakt:
raise Failed(f"({response.status_code}) {response.reason}") raise Failed(f"({response.status_code}) {response.reason}")
json_data = response.json() json_data = response.json()
if self.config.trace_mode: if self.config.trace_mode:
logger.debug(f"Headers: {response.headers}")
logger.debug(f"Response: {json_data}") logger.debug(f"Response: {json_data}")
if isinstance(json_data, dict): if isinstance(json_data, dict):
return json_data return json_data

Loading…
Cancel
Save