pull/1123/head
cpt-kuesel 2 years ago
commit c631fe390a

@ -1 +1 @@
1.17.3-develop133 1.17.3-develop138

@ -40,7 +40,7 @@ templates:
episode_air_date: <<last>> episode_air_date: <<last>>
plex_all: <<all>> plex_all: <<all>>
filters: filters:
tmdb_status1: <<tmdb>> tmdb_status: <<tmdb>>
overlays: overlays:

@ -24,7 +24,7 @@ variables:
item: Article item: Article
key_names: key_names:
Action: Action Action: Action
Actors: Acteurs et actrices Actors: Acteurs et Actrices
Adventure: Aventure Adventure: Aventure
Arabic: Arabes Arabic: Arabes
Audio Language: Langue audio Audio Language: Langue audio
@ -38,7 +38,7 @@ key_names:
Czech: Tchèques Czech: Tchèques
Danish: Danois Danish: Danois
Decade: Décennie Decade: Décennie
Directors: Directeurs et Directrices Directors: Réalisateurs
Drama: Dramatiques Drama: Dramatiques
Dutch: Néerlandais Dutch: Néerlandais
Easter: Pâques Easter: Pâques

@ -215,7 +215,9 @@ Tag search can take multiple values as a **list or a comma-separated string**.
| `decade` | Uses the year tag to match the decade | &#9989; | &#10060; | &#10060; | | `decade` | Uses the year tag to match the decade | &#9989; | &#10060; | &#10060; |
| `director` | Uses the director tags to match | &#9989; | &#10060; | &#10060; | | `director` | Uses the director tags to match | &#9989; | &#10060; | &#10060; |
| `genre` | Uses the genre tags to match | &#9989; | &#9989; | &#10060; | | `genre` | Uses the genre tags to match | &#9989; | &#9989; | &#10060; |
| `label` | Uses the label tags to match | &#9989; | &#9989; | &#10060; | | `label` | Uses the label tags to match for top level collections | &#9989; | &#9989; | &#10060; |
| `season_label` | Uses the label tags to match for season collections | &#10060; | &#9989; | &#10060; |
| `episode_label` | Uses the label tags to match for episode collections | &#10060; | &#9989; | &#10060; |
| `network` | Uses the network tags to match<br>**Only works with the New Plex TV Agent** | &#10060; | &#9989; | &#10060; | | `network` | Uses the network tags to match<br>**Only works with the New Plex TV Agent** | &#10060; | &#9989; | &#10060; |
| `producer` | Uses the actor tags to match | &#9989; | &#10060; | &#10060; | | `producer` | Uses the actor tags to match | &#9989; | &#10060; | &#10060; |
| `resolution` | Uses the resolution tags to match | &#9989; | &#9989; | &#10060; | | `resolution` | Uses the resolution tags to match | &#9989; | &#9989; | &#10060; |
@ -228,6 +230,7 @@ Tag search can take multiple values as a **list or a comma-separated string**.
| `artist_country` | Uses the Artist's Country attribute to match | &#10060; | &#10060; | &#9989; | | `artist_country` | Uses the Artist's Country attribute to match | &#10060; | &#10060; | &#9989; |
| `artist_mood` | Uses the Artist's Mood attribute to match | &#10060; | &#10060; | &#9989; | | `artist_mood` | Uses the Artist's Mood attribute to match | &#10060; | &#10060; | &#9989; |
| `artist_style` | Uses the Artist's Style attribute to match | &#10060; | &#10060; | &#9989; | | `artist_style` | Uses the Artist's Style attribute to match | &#10060; | &#10060; | &#9989; |
| `artist_label` | Uses the Artist's Label attribute to match | &#10060; | &#10060; | &#9989; |
| `album_genre` | Uses the Album's Genre attribute to match | &#10060; | &#10060; | &#9989; | | `album_genre` | Uses the Album's Genre attribute to match | &#10060; | &#10060; | &#9989; |
| `album_mood` | Uses the Album's Mood attribute to match | &#10060; | &#10060; | &#9989; | | `album_mood` | Uses the Album's Mood attribute to match | &#10060; | &#10060; | &#9989; |
| `album_style` | Uses the Album's Style attribute to match | &#10060; | &#10060; | &#9989; | | `album_style` | Uses the Album's Style attribute to match | &#10060; | &#10060; | &#9989; |
@ -238,6 +241,7 @@ Tag search can take multiple values as a **list or a comma-separated string**.
| `album_label` | Uses the Album's Label attribute to match | &#10060; | &#10060; | &#9989; | | `album_label` | Uses the Album's Label attribute to match | &#10060; | &#10060; | &#9989; |
| `track_mood` | Uses the Track's Mood attribute to match | &#10060; | &#10060; | &#9989; | | `track_mood` | Uses the Track's Mood attribute to match | &#10060; | &#10060; | &#9989; |
| `track_source` | Uses the Track's Style attribute to match | &#10060; | &#10060; | &#9989; | | `track_source` | Uses the Track's Style attribute to match | &#10060; | &#10060; | &#9989; |
| `track_label` | Uses the Track's Label attribute to match | &#10060; | &#10060; | &#9989; |
## Date Searches ## Date Searches

@ -156,7 +156,9 @@ Tag filter can take multiple values as a **list or a comma-separated string**.
| `decade` | Uses the year tag to match the decade | &#9989; | &#10060; | &#10060; | | `decade` | Uses the year tag to match the decade | &#9989; | &#10060; | &#10060; |
| `director` | Uses the director tags to match | &#9989; | &#10060; | &#10060; | | `director` | Uses the director tags to match | &#9989; | &#10060; | &#10060; |
| `genre` | Uses the genre tags to match | &#9989; | &#9989; | &#10060; | | `genre` | Uses the genre tags to match | &#9989; | &#9989; | &#10060; |
| `label` | Uses the label tags to match | &#9989; | &#9989; | &#10060; | | `label` | Uses the label tags to match for top level collections | &#9989; | &#9989; | &#10060; |
| `season_label` | Uses the label tags to match for season collections | &#10060; | &#9989; | &#10060; |
| `episode_label` | Uses the label tags to match for episode collections | &#10060; | &#9989; | &#10060; |
| `network` | Uses the network tags to match<br>**Only works with the New Plex TV Agent** | &#10060; | &#9989; | &#10060; | | `network` | Uses the network tags to match<br>**Only works with the New Plex TV Agent** | &#10060; | &#9989; | &#10060; |
| `producer` | Uses the actor tags to match | &#9989; | &#10060; | &#10060; | | `producer` | Uses the actor tags to match | &#9989; | &#10060; | &#10060; |
| `resolution` | Uses the resolution tags to match | &#9989; | &#9989; | &#10060; | | `resolution` | Uses the resolution tags to match | &#9989; | &#9989; | &#10060; |
@ -169,6 +171,7 @@ Tag filter can take multiple values as a **list or a comma-separated string**.
| `artist_country` | Uses the Artist's Country attribute to match | &#10060; | &#10060; | &#9989; | | `artist_country` | Uses the Artist's Country attribute to match | &#10060; | &#10060; | &#9989; |
| `artist_mood` | Uses the Artist's Mood attribute to match | &#10060; | &#10060; | &#9989; | | `artist_mood` | Uses the Artist's Mood attribute to match | &#10060; | &#10060; | &#9989; |
| `artist_style` | Uses the Artist's Style attribute to match | &#10060; | &#10060; | &#9989; | | `artist_style` | Uses the Artist's Style attribute to match | &#10060; | &#10060; | &#9989; |
| `artist_label` | Uses the Artist's Label attribute to match | &#10060; | &#10060; | &#9989; |
| `album_genre` | Uses the Album's Genre attribute to match | &#10060; | &#10060; | &#9989; | | `album_genre` | Uses the Album's Genre attribute to match | &#10060; | &#10060; | &#9989; |
| `album_mood` | Uses the Album's Mood attribute to match | &#10060; | &#10060; | &#9989; | | `album_mood` | Uses the Album's Mood attribute to match | &#10060; | &#10060; | &#9989; |
| `album_style` | Uses the Album's Style attribute to match | &#10060; | &#10060; | &#9989; | | `album_style` | Uses the Album's Style attribute to match | &#10060; | &#10060; | &#9989; |
@ -179,6 +182,7 @@ Tag filter can take multiple values as a **list or a comma-separated string**.
| `album_label` | Uses the Album's Label attribute to match | &#10060; | &#10060; | &#9989; | | `album_label` | Uses the Album's Label attribute to match | &#10060; | &#10060; | &#9989; |
| `track_mood` | Uses the Track's Mood attribute to match | &#10060; | &#10060; | &#9989; | | `track_mood` | Uses the Track's Mood attribute to match | &#10060; | &#10060; | &#9989; |
| `track_source` | Uses the Track's Style attribute to match | &#10060; | &#10060; | &#9989; | | `track_source` | Uses the Track's Style attribute to match | &#10060; | &#10060; | &#9989; |
| `track_label` | Uses the Track's Label attribute to match | &#10060; | &#10060; | &#9989; |
## Date Filters ## Date Filters

@ -1880,7 +1880,6 @@ class CollectionBuilder:
def build_url_arg(arg, mod=None, arg_s=None, mod_s=None): def build_url_arg(arg, mod=None, arg_s=None, mod_s=None):
arg_key = plex.search_translation[attr] if attr in plex.search_translation else attr arg_key = plex.search_translation[attr] if attr in plex.search_translation else attr
arg_key = f"{sort_type}.label" if arg_key == "label" and sort_type in ["season", "episode", "album", "track"] else arg_key
arg_key = plex.show_translation[arg_key] if self.library.is_show and arg_key in plex.show_translation else arg_key arg_key = plex.show_translation[arg_key] if self.library.is_show and arg_key in plex.show_translation else arg_key
if mod is None: if mod is None:
mod = plex.modifier_translation[modifier] if modifier in plex.modifier_translation else modifier mod = plex.modifier_translation[modifier] if modifier in plex.modifier_translation else modifier

@ -765,7 +765,10 @@ class ConfigFile:
"add_blank_entries": True "add_blank_entries": True
} }
if lib["operations"]["metadata_backup"] and isinstance(lib["operations"]["metadata_backup"], dict): if lib["operations"]["metadata_backup"] and isinstance(lib["operations"]["metadata_backup"], dict):
params["metadata_backup"]["path"] = check_for_attribute(lib["operations"]["metadata_backup"], "path", var_type="path", default=params["metadata_backup"]["path"], save=False) try:
params["metadata_backup"]["path"] = check_for_attribute(lib["operations"]["metadata_backup"], "path", var_type="path", save=False)
except Failed as e:
logger.debug(f"{e} using default {params['metadata_backup']['path']}")
params["metadata_backup"]["exclude"] = check_for_attribute(lib["operations"]["metadata_backup"], "exclude", var_type="comma_list", default_is_none=True, save=False) params["metadata_backup"]["exclude"] = check_for_attribute(lib["operations"]["metadata_backup"], "exclude", var_type="comma_list", default_is_none=True, save=False)
params["metadata_backup"]["sync_tags"] = check_for_attribute(lib["operations"]["metadata_backup"], "sync_tags", var_type="bool", default=False, save=False) params["metadata_backup"]["sync_tags"] = check_for_attribute(lib["operations"]["metadata_backup"], "sync_tags", var_type="bool", default=False, save=False)
params["metadata_backup"]["add_blank_entries"] = check_for_attribute(lib["operations"]["metadata_backup"], "add_blank_entries", var_type="bool", default=True, save=False) params["metadata_backup"]["add_blank_entries"] = check_for_attribute(lib["operations"]["metadata_backup"], "add_blank_entries", var_type="bool", default=True, save=False)

@ -262,12 +262,15 @@ class DataFile:
language = variables["language"] if "language" in variables else "default" language = variables["language"] if "language" in variables else "default"
translation_variables = {k: v[language if language in v else "default"] for k, v in self.translations.items()} translation_variables = {k: v[language if language in v else "default"] for k, v in self.translations.items()}
key_name_variables = {}
for var_key, var_value in self.key_names.items(): for var_key, var_value in self.key_names.items():
if var_key == "library_type" and language in var_value: if var_key == "library_type" and language in var_value:
variables[var_key] = var_value[language].lower() variables[var_key] = var_value[language].lower()
variables[f"{var_key}U"] = var_value[language] variables[f"{var_key}U"] = var_value[language]
elif language in var_value: elif language in var_value:
translation_variables[var_key] = var_value[language] key_name_variables[var_key] = var_value[language]
if "key_name" in variables and variables["key_name"] in key_name_variables:
variables["key_name"] = key_name_variables[variables["key_name"]]
def replace_var(input_item, search_dicts): def replace_var(input_item, search_dicts):
if not isinstance(search_dicts, list): if not isinstance(search_dicts, list):

@ -1,13 +1,16 @@
import os, re, time import os, re, time
from datetime import datetime from datetime import datetime
from PIL import Image, ImageColor, ImageDraw, ImageFont
from modules import util from modules import util
from modules.util import Failed from modules.util import Failed
from PIL import Image, ImageColor, ImageDraw, ImageFont
from plexapi.audio import Album
from plexapi.video import Episode
logger = util.logger logger = util.logger
portrait_dim = (1000, 1500) portrait_dim = (1000, 1500)
landscape_dim = (1920, 1080) landscape_dim = (1920, 1080)
square_dim = (1000, 1000)
old_special_text = [f"{a}{s}" for a in ["audience_rating", "critic_rating", "user_rating"] for s in ["", "0", "%", "#"]] old_special_text = [f"{a}{s}" for a in ["audience_rating", "critic_rating", "user_rating"] for s in ["", "0", "%", "#"]]
float_vars = ["audience_rating", "critic_rating", "user_rating"] float_vars = ["audience_rating", "critic_rating", "user_rating"]
int_vars = ["runtime", "season_number", "episode_number", "episode_count", "versions"] int_vars = ["runtime", "season_number", "episode_number", "episode_count", "versions"]
@ -106,6 +109,13 @@ def parse_cords(data, parent, required=False):
return horizontal_align, horizontal_offset, vertical_align, vertical_offset return horizontal_align, horizontal_offset, vertical_align, vertical_offset
def get_canvas_size(item):
if isinstance(item, Episode):
return landscape_dim
elif isinstance(item, Album):
return square_dim
else:
return portrait_dim
class Overlay: class Overlay:
def __init__(self, config, library, original_mapping_name, overlay_data, suppress, level): def __init__(self, config, library, original_mapping_name, overlay_data, suppress, level):
@ -122,6 +132,8 @@ class Overlay:
self.landscape_box = None self.landscape_box = None
self.portrait = None self.portrait = None
self.portrait_box = None self.portrait_box = None
self.square = None
self.square_box = None
self.group = None self.group = None
self.queue = None self.queue = None
self.weight = None self.weight = None
@ -326,9 +338,11 @@ class Overlay:
box = self.image.size if self.image else None box = self.image.size if self.image else None
self.portrait, self.portrait_box = self.get_backdrop(portrait_dim, box=box, text=self.name[5:-1]) self.portrait, self.portrait_box = self.get_backdrop(portrait_dim, box=box, text=self.name[5:-1])
self.landscape, self.landscape_box = self.get_backdrop(landscape_dim, box=box, text=self.name[5:-1]) self.landscape, self.landscape_box = self.get_backdrop(landscape_dim, box=box, text=self.name[5:-1])
self.square, self.square_box = self.get_backdrop(square_dim, box=box, text=self.name[5:-1])
elif self.name.startswith("backdrop"): elif self.name.startswith("backdrop"):
self.portrait, self.portrait_box = self.get_backdrop(portrait_dim, box=self.back_box) self.portrait, self.portrait_box = self.get_backdrop(portrait_dim, box=self.back_box)
self.landscape, self.landscape_box = self.get_backdrop(landscape_dim, box=self.back_box) self.landscape, self.landscape_box = self.get_backdrop(landscape_dim, box=self.back_box)
self.square, self.square_box = self.get_backdrop(square_dim, box=self.back_box)
else: else:
if not self.path: if not self.path:
clean_name, _ = util.validate_filename(self.name) clean_name, _ = util.validate_filename(self.name)
@ -345,6 +359,7 @@ class Overlay:
if self.has_coordinates(): if self.has_coordinates():
self.portrait, self.portrait_box = self.get_backdrop(portrait_dim, box=self.image.size) self.portrait, self.portrait_box = self.get_backdrop(portrait_dim, box=self.image.size)
self.landscape, self.landscape_box = self.get_backdrop(landscape_dim, box=self.image.size) self.landscape, self.landscape_box = self.get_backdrop(landscape_dim, box=self.image.size)
self.square, self.square_box = self.get_backdrop(square_dim, box=self.image.size)
if self.config.Cache: if self.config.Cache:
self.config.Cache.update_image_map(self.mapping_name, f"{self.library.image_table_name}_overlays", self.mapping_name, overlay_size) self.config.Cache.update_image_map(self.mapping_name, f"{self.library.image_table_name}_overlays", self.mapping_name, overlay_size)
except OSError: except OSError:
@ -500,3 +515,11 @@ class Overlay:
else: else:
ha, ho, va, vo = new_cords ha, ho, va, vo = new_cords
return get_cord(ho, canvas_box[0], box[0], ha), get_cord(vo, canvas_box[1], box[1], va) return get_cord(ho, canvas_box[0], box[0], ha), get_cord(vo, canvas_box[1], box[1], va)
def get_canvas(self, item):
if isinstance(item, Episode):
return self.landscape, self.landscape_box
elif isinstance(item, Album):
return self.square, self.square_box
else:
return self.portrait, self.portrait_box

@ -193,8 +193,7 @@ class Overlays:
logger.error(f"{item_title[:60]:<60} | Overlay Error: No poster found") logger.error(f"{item_title[:60]:<60} | Overlay Error: No poster found")
elif self.library.reapply_overlays or changed_image or overlay_change: elif self.library.reapply_overlays or changed_image or overlay_change:
try: try:
canvas_width = 1920 if isinstance(item, Episode) else 1000 canvas_width, canvas_height = overlay.get_canvas_size(item)
canvas_height = 1080 if isinstance(item, Episode) else 1500
new_poster = Image.open(poster.location if poster else has_original) \ new_poster = Image.open(poster.location if poster else has_original) \
.convert("RGB").resize((canvas_width, canvas_height), Image.ANTIALIAS) .convert("RGB").resize((canvas_width, canvas_height), Image.ANTIALIAS)
@ -296,20 +295,18 @@ class Overlays:
continue continue
new_poster.paste(overlay_image, (0, 0), overlay_image) new_poster.paste(overlay_image, (0, 0), overlay_image)
else: else:
overlay_image = current_overlay.landscape if isinstance(item, Episode) else current_overlay.portrait overlay_image, addon_box = current_overlay.get_canvas(item)
addon_box = current_overlay.landscape_box if isinstance(item, Episode) else current_overlay.portrait_box
new_poster.paste(overlay_image, (0, 0), overlay_image) new_poster.paste(overlay_image, (0, 0), overlay_image)
if current_overlay.image: if current_overlay.image:
new_poster.paste(current_overlay.image, addon_box, current_overlay.image) new_poster.paste(current_overlay.image, addon_box, current_overlay.image)
elif current_overlay.name == "backdrop": elif current_overlay.name == "backdrop":
overlay_image = current_overlay.landscape if isinstance(item, Episode) else current_overlay.portrait overlay_image, _ = current_overlay.get_canvas(item)
new_poster.paste(overlay_image, (0, 0), overlay_image) new_poster.paste(overlay_image, (0, 0), overlay_image)
else: else:
if current_overlay.has_coordinates(): if current_overlay.has_coordinates():
overlay_image, overlay_box = current_overlay.get_canvas(item)
if current_overlay.portrait is not None: if current_overlay.portrait is not None:
overlay_image = current_overlay.landscape if isinstance(item, Episode) else current_overlay.portrait
new_poster.paste(overlay_image, (0, 0), overlay_image) new_poster.paste(overlay_image, (0, 0), overlay_image)
overlay_box = current_overlay.landscape_box if isinstance(item, Episode) else current_overlay.portrait_box
new_poster.paste(current_overlay.image, overlay_box, current_overlay.image) new_poster.paste(current_overlay.image, overlay_box, current_overlay.image)
else: else:
new_poster = new_poster.resize(current_overlay.image.size, Image.ANTIALIAS) new_poster = new_poster.resize(current_overlay.image.size, Image.ANTIALIAS)

@ -51,6 +51,8 @@ search_translation = {
"unplayed_episodes": "show.unwatchedLeaves", "unplayed_episodes": "show.unwatchedLeaves",
"season_collection": "season.collection", "season_collection": "season.collection",
"episode_collection": "episode.collection", "episode_collection": "episode.collection",
"season_label": "season.label",
"episode_label": "episode.label",
"artist_title": "artist.title", "artist_title": "artist.title",
"artist_user_rating": "artist.userRating", "artist_user_rating": "artist.userRating",
"artist_genre": "artist.genre", "artist_genre": "artist.genre",
@ -61,6 +63,7 @@ search_translation = {
"artist_added": "artist.addedAt", "artist_added": "artist.addedAt",
"artist_last_played": "artist.lastViewedAt", "artist_last_played": "artist.lastViewedAt",
"artist_unmatched": "artist.unmatched", "artist_unmatched": "artist.unmatched",
"artist_label": "artist.label",
"album_title": "album.title", "album_title": "album.title",
"album_year": "album.year", "album_year": "album.year",
"album_decade": "album.decade", "album_decade": "album.decade",
@ -90,7 +93,8 @@ search_translation = {
"track_last_rated": "track.lastRatedAt", "track_last_rated": "track.lastRatedAt",
"track_added": "track.addedAt", "track_added": "track.addedAt",
"track_trash": "track.trash", "track_trash": "track.trash",
"track_source": "track.source" "track_source": "track.source",
"track_label": "track.label"
} }
show_translation = { show_translation = {
"title": "show.title", "title": "show.title",
@ -254,6 +258,8 @@ show_only_searches = [
"network", "network.not", "network", "network.not",
"season_collection", "season_collection.not", "season_collection", "season_collection.not",
"episode_collection", "episode_collection.not", "episode_collection", "episode_collection.not",
"season_label", "season_label.not",
"episode_label", "episode_label.not",
"episode_title", "episode_title.not", "episode_title.is", "episode_title.isnot", "episode_title.begins", "episode_title.ends", "episode_title", "episode_title.not", "episode_title.is", "episode_title.isnot", "episode_title.begins", "episode_title.ends",
"episode_added", "episode_added.not", "episode_added.before", "episode_added.after", "episode_added", "episode_added.not", "episode_added.before", "episode_added.after",
"episode_air_date", "episode_air_date.not", "episode_air_date", "episode_air_date.not",
@ -291,8 +297,8 @@ search_display = {"added": "Date Added", "release": "Release Date", "hdr": "HDR"
tag_attributes = [ tag_attributes = [
"actor", "audio_language", "collection", "content_rating", "country", "director", "genre", "label", "network", "actor", "audio_language", "collection", "content_rating", "country", "director", "genre", "label", "network",
"producer", "resolution", "studio", "subtitle_language", "writer", "season_collection", "episode_collection", "edition", "producer", "resolution", "studio", "subtitle_language", "writer", "season_collection", "episode_collection", "edition",
"artist_genre", "artist_collection", "artist_country", "artist_mood", "artist_style", "album_genre", "album_mood", "artist_genre", "artist_collection", "artist_country", "artist_mood", "artist_label", "artist_style", "album_genre", "album_mood",
"album_style", "album_format", "album_type", "album_collection", "album_source", "album_label", "track_mood", "track_source" "album_style", "album_format", "album_type", "album_collection", "album_source", "album_label", "track_mood", "track_source", "track_label"
] ]
tag_modifiers = ["", ".not", ".regex"] tag_modifiers = ["", ".not", ".regex"]
no_not_mods = ["resolution", "decade", "album_decade"] no_not_mods = ["resolution", "decade", "album_decade"]

Loading…
Cancel
Save