mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
Merge branch 'nightly' of https://github.com/meisnate12/Plex-Meta-Manager into nightly
This commit is contained in:
commit
c631fe390a
11 changed files with 59 additions and 20 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.17.3-develop133
|
||||
1.17.3-develop138
|
||||
|
|
|
@ -40,7 +40,7 @@ templates:
|
|||
episode_air_date: <<last>>
|
||||
plex_all: <<all>>
|
||||
filters:
|
||||
tmdb_status1: <<tmdb>>
|
||||
tmdb_status: <<tmdb>>
|
||||
|
||||
overlays:
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ variables:
|
|||
item: Article
|
||||
key_names:
|
||||
Action: Action
|
||||
Actors: Acteurs et actrices
|
||||
Actors: Acteurs et Actrices
|
||||
Adventure: Aventure
|
||||
Arabic: Arabes
|
||||
Audio Language: Langue audio
|
||||
|
@ -38,7 +38,7 @@ key_names:
|
|||
Czech: Tchèques
|
||||
Danish: Danois
|
||||
Decade: Décennie
|
||||
Directors: Directeurs et Directrices
|
||||
Directors: Réalisateurs
|
||||
Drama: Dramatiques
|
||||
Dutch: Néerlandais
|
||||
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 | ✅ | ❌ | ❌ |
|
||||
| `director` | Uses the director tags to match | ✅ | ❌ | ❌ |
|
||||
| `genre` | Uses the genre tags to match | ✅ | ✅ | ❌ |
|
||||
| `label` | Uses the label tags to match | ✅ | ✅ | ❌ |
|
||||
| `label` | Uses the label tags to match for top level collections | ✅ | ✅ | ❌ |
|
||||
| `season_label` | Uses the label tags to match for season collections | ❌ | ✅ | ❌ |
|
||||
| `episode_label` | Uses the label tags to match for episode collections | ❌ | ✅ | ❌ |
|
||||
| `network` | Uses the network tags to match<br>**Only works with the New Plex TV Agent** | ❌ | ✅ | ❌ |
|
||||
| `producer` | Uses the actor tags to match | ✅ | ❌ | ❌ |
|
||||
| `resolution` | Uses the resolution tags to match | ✅ | ✅ | ❌ |
|
||||
|
@ -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 | ❌ | ❌ | ✅ |
|
||||
| `artist_mood` | Uses the Artist's Mood attribute to match | ❌ | ❌ | ✅ |
|
||||
| `artist_style` | Uses the Artist's Style attribute to match | ❌ | ❌ | ✅ |
|
||||
| `artist_label` | Uses the Artist's Label attribute to match | ❌ | ❌ | ✅ |
|
||||
| `album_genre` | Uses the Album's Genre attribute to match | ❌ | ❌ | ✅ |
|
||||
| `album_mood` | Uses the Album's Mood attribute to match | ❌ | ❌ | ✅ |
|
||||
| `album_style` | Uses the Album's Style attribute to match | ❌ | ❌ | ✅ |
|
||||
|
@ -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 | ❌ | ❌ | ✅ |
|
||||
| `track_mood` | Uses the Track's Mood attribute to match | ❌ | ❌ | ✅ |
|
||||
| `track_source` | Uses the Track's Style attribute to match | ❌ | ❌ | ✅ |
|
||||
| `track_label` | Uses the Track's Label attribute to match | ❌ | ❌ | ✅ |
|
||||
|
||||
## 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 | ✅ | ❌ | ❌ |
|
||||
| `director` | Uses the director tags to match | ✅ | ❌ | ❌ |
|
||||
| `genre` | Uses the genre tags to match | ✅ | ✅ | ❌ |
|
||||
| `label` | Uses the label tags to match | ✅ | ✅ | ❌ |
|
||||
| `label` | Uses the label tags to match for top level collections | ✅ | ✅ | ❌ |
|
||||
| `season_label` | Uses the label tags to match for season collections | ❌ | ✅ | ❌ |
|
||||
| `episode_label` | Uses the label tags to match for episode collections | ❌ | ✅ | ❌ |
|
||||
| `network` | Uses the network tags to match<br>**Only works with the New Plex TV Agent** | ❌ | ✅ | ❌ |
|
||||
| `producer` | Uses the actor tags to match | ✅ | ❌ | ❌ |
|
||||
| `resolution` | Uses the resolution tags to match | ✅ | ✅ | ❌ |
|
||||
|
@ -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 | ❌ | ❌ | ✅ |
|
||||
| `artist_mood` | Uses the Artist's Mood attribute to match | ❌ | ❌ | ✅ |
|
||||
| `artist_style` | Uses the Artist's Style attribute to match | ❌ | ❌ | ✅ |
|
||||
| `artist_label` | Uses the Artist's Label attribute to match | ❌ | ❌ | ✅ |
|
||||
| `album_genre` | Uses the Album's Genre attribute to match | ❌ | ❌ | ✅ |
|
||||
| `album_mood` | Uses the Album's Mood attribute to match | ❌ | ❌ | ✅ |
|
||||
| `album_style` | Uses the Album's Style attribute to match | ❌ | ❌ | ✅ |
|
||||
|
@ -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 | ❌ | ❌ | ✅ |
|
||||
| `track_mood` | Uses the Track's Mood attribute to match | ❌ | ❌ | ✅ |
|
||||
| `track_source` | Uses the Track's Style attribute to match | ❌ | ❌ | ✅ |
|
||||
| `track_label` | Uses the Track's Label attribute to match | ❌ | ❌ | ✅ |
|
||||
|
||||
## Date Filters
|
||||
|
||||
|
|
|
@ -1880,7 +1880,6 @@ class CollectionBuilder:
|
|||
|
||||
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 = 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
|
||||
if mod is None:
|
||||
mod = plex.modifier_translation[modifier] if modifier in plex.modifier_translation else modifier
|
||||
|
|
|
@ -765,7 +765,10 @@ class ConfigFile:
|
|||
"add_blank_entries": True
|
||||
}
|
||||
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"]["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)
|
||||
|
|
|
@ -262,12 +262,15 @@ class DataFile:
|
|||
|
||||
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()}
|
||||
key_name_variables = {}
|
||||
for var_key, var_value in self.key_names.items():
|
||||
if var_key == "library_type" and language in var_value:
|
||||
variables[var_key] = var_value[language].lower()
|
||||
variables[f"{var_key}U"] = var_value[language]
|
||||
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):
|
||||
if not isinstance(search_dicts, list):
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import os, re, time
|
||||
from datetime import datetime
|
||||
from PIL import Image, ImageColor, ImageDraw, ImageFont
|
||||
from modules import util
|
||||
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
|
||||
|
||||
portrait_dim = (1000, 1500)
|
||||
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", "%", "#"]]
|
||||
float_vars = ["audience_rating", "critic_rating", "user_rating"]
|
||||
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
|
||||
|
||||
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:
|
||||
def __init__(self, config, library, original_mapping_name, overlay_data, suppress, level):
|
||||
|
@ -122,6 +132,8 @@ class Overlay:
|
|||
self.landscape_box = None
|
||||
self.portrait = None
|
||||
self.portrait_box = None
|
||||
self.square = None
|
||||
self.square_box = None
|
||||
self.group = None
|
||||
self.queue = None
|
||||
self.weight = None
|
||||
|
@ -326,9 +338,11 @@ class Overlay:
|
|||
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.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"):
|
||||
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.square, self.square_box = self.get_backdrop(square_dim, box=self.back_box)
|
||||
else:
|
||||
if not self.path:
|
||||
clean_name, _ = util.validate_filename(self.name)
|
||||
|
@ -345,6 +359,7 @@ class Overlay:
|
|||
if self.has_coordinates():
|
||||
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.square, self.square_box = self.get_backdrop(square_dim, box=self.image.size)
|
||||
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)
|
||||
except OSError:
|
||||
|
@ -500,3 +515,11 @@ class Overlay:
|
|||
else:
|
||||
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)
|
||||
|
||||
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")
|
||||
elif self.library.reapply_overlays or changed_image or overlay_change:
|
||||
try:
|
||||
canvas_width = 1920 if isinstance(item, Episode) else 1000
|
||||
canvas_height = 1080 if isinstance(item, Episode) else 1500
|
||||
canvas_width, canvas_height = overlay.get_canvas_size(item)
|
||||
|
||||
new_poster = Image.open(poster.location if poster else has_original) \
|
||||
.convert("RGB").resize((canvas_width, canvas_height), Image.ANTIALIAS)
|
||||
|
@ -296,20 +295,18 @@ class Overlays:
|
|||
continue
|
||||
new_poster.paste(overlay_image, (0, 0), overlay_image)
|
||||
else:
|
||||
overlay_image = current_overlay.landscape if isinstance(item, Episode) else current_overlay.portrait
|
||||
addon_box = current_overlay.landscape_box if isinstance(item, Episode) else current_overlay.portrait_box
|
||||
overlay_image, addon_box = current_overlay.get_canvas(item)
|
||||
new_poster.paste(overlay_image, (0, 0), overlay_image)
|
||||
if current_overlay.image:
|
||||
new_poster.paste(current_overlay.image, addon_box, current_overlay.image)
|
||||
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)
|
||||
else:
|
||||
if current_overlay.has_coordinates():
|
||||
overlay_image, overlay_box = current_overlay.get_canvas(item)
|
||||
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)
|
||||
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)
|
||||
else:
|
||||
new_poster = new_poster.resize(current_overlay.image.size, Image.ANTIALIAS)
|
||||
|
|
|
@ -51,6 +51,8 @@ search_translation = {
|
|||
"unplayed_episodes": "show.unwatchedLeaves",
|
||||
"season_collection": "season.collection",
|
||||
"episode_collection": "episode.collection",
|
||||
"season_label": "season.label",
|
||||
"episode_label": "episode.label",
|
||||
"artist_title": "artist.title",
|
||||
"artist_user_rating": "artist.userRating",
|
||||
"artist_genre": "artist.genre",
|
||||
|
@ -61,6 +63,7 @@ search_translation = {
|
|||
"artist_added": "artist.addedAt",
|
||||
"artist_last_played": "artist.lastViewedAt",
|
||||
"artist_unmatched": "artist.unmatched",
|
||||
"artist_label": "artist.label",
|
||||
"album_title": "album.title",
|
||||
"album_year": "album.year",
|
||||
"album_decade": "album.decade",
|
||||
|
@ -90,7 +93,8 @@ search_translation = {
|
|||
"track_last_rated": "track.lastRatedAt",
|
||||
"track_added": "track.addedAt",
|
||||
"track_trash": "track.trash",
|
||||
"track_source": "track.source"
|
||||
"track_source": "track.source",
|
||||
"track_label": "track.label"
|
||||
}
|
||||
show_translation = {
|
||||
"title": "show.title",
|
||||
|
@ -254,6 +258,8 @@ show_only_searches = [
|
|||
"network", "network.not",
|
||||
"season_collection", "season_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_added", "episode_added.not", "episode_added.before", "episode_added.after",
|
||||
"episode_air_date", "episode_air_date.not",
|
||||
|
@ -291,8 +297,8 @@ search_display = {"added": "Date Added", "release": "Release Date", "hdr": "HDR"
|
|||
tag_attributes = [
|
||||
"actor", "audio_language", "collection", "content_rating", "country", "director", "genre", "label", "network",
|
||||
"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",
|
||||
"album_style", "album_format", "album_type", "album_collection", "album_source", "album_label", "track_mood", "track_source"
|
||||
"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", "track_label"
|
||||
]
|
||||
tag_modifiers = ["", ".not", ".regex"]
|
||||
no_not_mods = ["resolution", "decade", "album_decade"]
|
||||
|
|
Loading…
Reference in a new issue