mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
[11] update to special_text overlays
This commit is contained in:
parent
f44589e853
commit
c0a372382e
7 changed files with 173 additions and 147 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.17.2-develop10
|
||||
1.17.2-develop11
|
||||
|
|
|
@ -93,7 +93,7 @@ There are many attributes available when using overlays to edit how they work.
|
|||
| `back_radius` | Backdrop Radius for the Text Overlay.<br>**Value:** Integer greater than 0 | ❌ |
|
||||
| `back_line_color` | Backdrop Line Color for the Text Overlay.<br>**Value:** Color Hex Code in format `#RGB`, `#RGBA`, `#RRGGBB` or `#RRGGBBAA`. | ❌ |
|
||||
| `back_line_width` | Backdrop Line Width for the Text Overlay.<br>**Value:** Integer greater than 0 | ❌ |
|
||||
| `text_format` | Text Format for Special Text Overlays.<br>**`text_format` Only works with text overlays**<br>**Value:** Integer 0 or greater | ❌ |
|
||||
| `special_text` | Text Format for Special Text Overlays.<br>**`special_text` Only works with text overlays** | ❌ |
|
||||
| `addon_offset` | Text Addon Image Offset from the text.<br>**`addon_offset` Only works with text overlays**<br>**Value:** Integer 0 or greater | ❌ |
|
||||
| `addon_position` | Text Addon Image Alignment in relation to the text.<br>**`addon_position` Only works with text overlays**<br>**Values:** `left`, `right`, `top`, `bottom` | ❌ |
|
||||
|
||||
|
@ -171,26 +171,26 @@ overlays:
|
|||
|
||||
#### Special Text Overlays
|
||||
|
||||
You can use the item's metadata to determine the text.
|
||||
You can use the item's metadata to determine the text. You set the `name` to `text(special_text)` and then use the `special_text` attribute to format the text.
|
||||
|
||||
The final text can be formatted using the `text_format` attribute and the format variables.
|
||||
There are multiple Special Text Variables that can be used when formatting the text. The variables are defined like so `<<name>>` and some can have modifiers like so `<<name$>>` where `$` is the modifier. The available options are:
|
||||
|
||||
The available options are:
|
||||
| Special Text Variables | Format Variables & Mods | Movies | Shows | Seasons | Episodes |
|
||||
|:-----------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:--------:|:--------:|:--------:|
|
||||
| audience_rating | `<<audience_rating>>`: audience rating (`8.7`, `9.0`)<br>`<<audience_rating%>>`: audience rating out of 100 (`87`, `90`)<br>`<<audience_rating#>>`: audience rating removing `.0` as needed (`8.7`, `9`) | ✅ | ✅ | ❌ | ✅ |
|
||||
| critic_rating | `<<critic_rating>>`: critic rating (`8.7`, `9.0`)<br>`<<critic_rating%>>`: critic rating out of 100 (`87`, `90`)<br>`<<critic_rating#>>`: critic rating removing `.0` as needed (`8.7`, `9`) | ✅ | ✅ | ❌ | ✅ |
|
||||
| user_rating | `<<user_rating>>`: user rating (`8.7`, `9.0`)<br>`<<user_rating%>>`: user rating out of 100 (`87`, `90`)<br>`<<user_rating#>>`: user rating removing `.0` as needed (`8.7`, `9`) | ✅ | ✅ | ✅ | ✅ |
|
||||
| title | `<<title>>`: Title of the Item | ✅ | ✅ | ✅ | ✅ |
|
||||
| show_title | `<<show_title>>`: Title of the Item's Show | ❌ | ❌ | ✅ | ✅ |
|
||||
| season_title | `<<season_title>>`: Title of the Item's Season | ❌ | ❌ | ❌ | ✅ |
|
||||
| original_title | `<<original_title>>`: Original Title of the Item | ✅ | ✅ | ❌ | ❌ |
|
||||
| content_rating | `<<content_rating>>`: Content Rating of the Item | ✅ | ✅ | ❌ | ✅ |
|
||||
| episode_count | `<<episode_count>>`: Number of Episodes (`1`)<br>`<<episode_countW>`: Number of Episodes As Words (`One`)<br>`<<episode_count0>`: Number of Episodes With 10s Padding (`01`)<br>`<<episode_count00>>`: Number of Episodes With 100s Padding (`001`) | ❌ | ✅ | ✅ | ❌ |
|
||||
| season_number | `<<season_number>>`: Season Number (`1`)<br>`<<season_numberW>`: Season Number As Words (`One`)<br>`<<season_number0>`: Season Number With 10s Padding (`01`)<br>`<<season_number00>>`: Season Number With 100s Padding (`001`) | ❌ | ❌ | ✅ | ✅ |
|
||||
| episode_number | `<<episode_number>>`: Episode Number (`1`)<br>`<<episode_numberW>`: Episode Number As Words (`One`)<br>`<<episode_number0>`: Episode Number With 10s Padding (`01`)<br>`<<episode_number00>>`: Episode Number With 100s Padding (`001`) | ❌ | ❌ | ❌ | ✅ |
|
||||
| runtime | `<<runtime>>`: Runtime of the Item in minutes<br>`<<runtimeH>>`: Hours in runtime of the Item<br>`<<runtimeM>>`: Minutes remaining in the hour in the runtime of the Item | ✅ | ❌ | ❌ | ✅ |
|
||||
| originally_available | `<<originally_available>>`: Original Available Date of the Item<br>`<<originally_available[DATE_FORMAT_STRING]>>`: Original Available Date of the Item in the given format. [Format Options](https://strftime.org/) | ✅ | ✅ | ❌ | ✅ |
|
||||
|
||||
| Attribute | Notes | Format Variables |
|
||||
|:---------------------------|:-------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| text(audience_rating) | Doesnt work with Seasons | `<<value>>` -> ratings (`8.7`, `9.0`)<br>`<<value%>>` -> rating out of 100 (`87`, `90`)<br>`<<value#>>` -> rating removing `.0` as needed (`8.7`, `9`) |
|
||||
| text(critic_rating) | Doesnt work with Seasons | `<<value>>` -> ratings (`8.7`, `9.0`)<br>`<<value%>>` -> rating out of 100 (`87`, `90`)<br>`<<value#>>` -> rating removing `.0` as needed (`8.7`, `9`) |
|
||||
| text(user_rating) | | `<<value>>` -> ratings (`8.7`, `9.0`)<br>`<<value%>>` -> rating out of 100 (`87`, `90`)<br>`<<value#>>` -> rating removing `.0` as needed (`8.7`, `9`) |
|
||||
| text(title) | | `<<value>>` -> Title of the Item |
|
||||
| text(show_title) | Doesnt work with Movies and Shows | `<<value>>` -> Title of the Item's Show |
|
||||
| text(season_title) | Only works with Episodes | `<<value>>` -> Title of the Item's Season |
|
||||
| text(original_title) | Only works with Movies and Shows | `<<value>>` -> Original Title of the Item |
|
||||
| text(episode_count) | Only works with Shows and Seasons | `<<value>>` -> Number of Episodes in the Show or Season |
|
||||
| text(content_rating) | Doesnt work with Seasons | `<<value>>` -> Content Rating of the Item |
|
||||
| text(season_episode) | Only works with Seasons and Episodes | `<<season>>` -> Season Number<br>`<<season0>` -> Season Number With 10s Padding<br>`<<season00>>` -> Season Number With 100s Padding<br>`<<episode>>` -> Episode Number<br>`<<episode0>` -> Episode Number With 10s Padding<br>`<<episode00>>` -> Episode Number With 100s Padding |
|
||||
| text(runtime) | Doesnt work with Shows and Seasons | `<<value>>` -> Runtime of the Item in minutes<br>`<<valueH>>` -> Hours in runtime of the Item<br>`<<valueM>>` -> Minutes remaining in the hour in the runtime of the Item |
|
||||
| text(originally_available) | Doesnt work with Seasons | `<<value>>` -> Original Available Date of the Item<br>`<<value[DATE_FORMAT_STRING]>>` -> Original Available Date of the Item in the given format. [Format Options](https://strftime.org/) |
|
||||
|
||||
Note: 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.
|
||||
|
||||
|
@ -200,8 +200,8 @@ I want to have the audience_rating display with a `%` out of 100 vs 0.0-10.0.
|
|||
overlays:
|
||||
audience_rating:
|
||||
overlay:
|
||||
name: text(audience_rating)
|
||||
text_format: <<value%>>%
|
||||
name: text(special_text)
|
||||
special_text: <<audience_rating%>>%
|
||||
horizontal_offset: 225
|
||||
horizontal_align: center
|
||||
vertical_offset: 15
|
||||
|
|
|
@ -260,7 +260,6 @@ class CollectionBuilder:
|
|||
if level and not self.library.is_movie and not self.playlist:
|
||||
logger.debug("")
|
||||
logger.debug("Validating Method: builder_level")
|
||||
level = self.data[methods["builder_level"]]
|
||||
if level is None:
|
||||
logger.error(f"{self.Type} Error: builder_level attribute is blank")
|
||||
else:
|
||||
|
@ -1670,6 +1669,20 @@ class CollectionBuilder:
|
|||
item = self.fetch_item(rk)
|
||||
if self.playlist and isinstance(item, (Show, Season)):
|
||||
items.extend(item.episodes())
|
||||
elif self.builder_level == "movie" and not isinstance(item, Movie):
|
||||
logger.info(f"Item: {item} is not an Movie")
|
||||
elif self.builder_level == "show" and not isinstance(item, Show):
|
||||
logger.info(f"Item: {item} is not an Show")
|
||||
elif self.builder_level == "episode" and not isinstance(item, Episode):
|
||||
logger.info(f"Item: {item} is not an Episode")
|
||||
elif self.builder_level == "season" and not isinstance(item, Season):
|
||||
logger.info(f"Item: {item} is not a Season")
|
||||
elif self.builder_level == "artist" and not isinstance(item, Artist):
|
||||
logger.info(f"Item: {item} is not an Artist")
|
||||
elif self.builder_level == "album" and not isinstance(item, Album):
|
||||
logger.info(f"Item: {item} is not an Album")
|
||||
elif self.builder_level == "track" and not isinstance(item, Track):
|
||||
logger.info(f"Item: {item} is not a Track")
|
||||
else:
|
||||
items.append(item)
|
||||
except Failed as e:
|
||||
|
|
|
@ -867,16 +867,16 @@ class Cache:
|
|||
[(r.name, r.date.strftime("%Y-%m-%d") if r.date else None,
|
||||
expiration_date.strftime("%Y-%m-%d"), r.season, r.round) for r in races])
|
||||
|
||||
def query_overlay_special_text(self, rating_key, data_type):
|
||||
rating = None
|
||||
def query_overlay_special_text(self, rating_key):
|
||||
attrs = {}
|
||||
with sqlite3.connect(self.cache_path) as connection:
|
||||
connection.row_factory = sqlite3.Row
|
||||
with closing(connection.cursor()) as cursor:
|
||||
cursor.execute("SELECT * FROM overlay_special_text WHERE rating_key = ? AND type = ?", (rating_key, data_type))
|
||||
row = cursor.fetchone()
|
||||
cursor.execute("SELECT * FROM overlay_special_text WHERE rating_key = ?", (rating_key, ))
|
||||
for row in cursor.fetchall():
|
||||
if row:
|
||||
rating = row["text"]
|
||||
return rating
|
||||
attrs[row["type"]] = row["text"]
|
||||
return attrs
|
||||
|
||||
def update_overlay_special_text(self, rating_key, data_type, text):
|
||||
with sqlite3.connect(self.cache_path) as connection:
|
||||
|
|
|
@ -8,12 +8,43 @@ logger = util.logger
|
|||
|
||||
portrait_dim = (1000, 1500)
|
||||
landscape_dim = (1920, 1080)
|
||||
rating_special_text = [f"text({a})" for a in ["audience_rating", "critic_rating", "user_rating"]]
|
||||
value_overlays = ["title", "show_title", "season_title", "original_title", "episode_count", "content_rating"]
|
||||
special_overlays = ["season_episode", "runtime", "originally_available"]
|
||||
special_text_overlays = [f"text({a})" for a in value_overlays + special_overlays] + rating_special_text
|
||||
old_special_text = [f"text({a}{s})" for a in ["audience_rating", "critic_rating", "user_rating"] for s in ["0", "%", "#"]]
|
||||
all_special_text = special_text_overlays + old_special_text
|
||||
old_special_text2 = [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"]
|
||||
date_vars = ["originally_available"]
|
||||
types_for_var = {
|
||||
"movie_show_season_episode_artist_album": ["user_rating", "title"],
|
||||
"movie_show_episode_album": ["critic_rating", "originally_available"],
|
||||
"movie_show_episode": ["audience_rating", "content_rating"],
|
||||
"movie_show": ["original_title"],
|
||||
"movie_episode": ["runtime"],
|
||||
"season_episode": ["show_title", "season_number"],
|
||||
"show_season": ["episode_count"],
|
||||
"episode": ["season_title", "episode_number"]
|
||||
}
|
||||
var_mods = {
|
||||
"title": [""],
|
||||
"content_rating": [""],
|
||||
"original_title": [""],
|
||||
"show_title": [""],
|
||||
"season_title": [""],
|
||||
"user_rating": ["", "%", "#"],
|
||||
"critic_rating": ["", "%", "#"],
|
||||
"audience_rating": ["", "%", "#"],
|
||||
"originally_available": ["", "["],
|
||||
"runtime": ["", "H", "M"],
|
||||
"season_number": ["", "W", "0", "00"],
|
||||
"episode_number": ["", "W", "0", "00"],
|
||||
"episode_count": ["", "W", "0", "00"],
|
||||
}
|
||||
vars_by_type = {
|
||||
"movie": [f"{item}{m}" for check, sub in types_for_var.items() for item in sub for m in var_mods[item] if "movie" in check],
|
||||
"show": [f"{item}{m}" for check, sub in types_for_var.items() for item in sub for m in var_mods[item] if "show" in check],
|
||||
"season": [f"{item}{m}" for check, sub in types_for_var.items() for item in sub for m in var_mods[item] if "season" in check],
|
||||
"episode": [f"{item}{m}" for check, sub in types_for_var.items() for item in sub for m in var_mods[item] if "episode" in check],
|
||||
"artist": [f"{item}{m}" for check, sub in types_for_var.items() for item in sub for m in var_mods[item] if "artist" in check],
|
||||
"album": [f"{item}{m}" for check, sub in types_for_var.items() for item in sub for m in var_mods[item] if "album" in check],
|
||||
}
|
||||
|
||||
def parse_cords(data, parent, required=False):
|
||||
horizontal_align = util.parse("Overlay", "horizontal_align", data["horizontal_align"], parent=parent,
|
||||
|
@ -95,7 +126,7 @@ class Overlay:
|
|||
self.font_color = None
|
||||
self.addon_offset = 0
|
||||
self.addon_position = None
|
||||
self.text_overlay_format = None
|
||||
self.special_text = None
|
||||
|
||||
logger.debug("")
|
||||
logger.debug("Validating Method: overlay")
|
||||
|
@ -223,6 +254,7 @@ class Overlay:
|
|||
if not match:
|
||||
raise Failed(f"Overlay Error: failed to parse overlay text name: {self.name}")
|
||||
self.name = f"text({match.group(1)})"
|
||||
text = f"{match.group(1)}"
|
||||
self.font_name = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "fonts", "Roboto-Medium.ttf")
|
||||
if "font_size" in self.data:
|
||||
self.font_size = util.parse("Overlay", "font_size", self.data["font_size"], datatype="int", parent="overlay", default=self.font_size)
|
||||
|
@ -249,52 +281,23 @@ class Overlay:
|
|||
self.font_color = ImageColor.getcolor(self.data["font_color"], "RGBA")
|
||||
except ValueError:
|
||||
raise Failed(f"Overlay Error: overlay font_color: {self.data['font_color']} invalid")
|
||||
|
||||
if self.name in all_special_text:
|
||||
if self.name.startswith("text(critic") and self.level == "season":
|
||||
raise Failed("Overlay Error: builder_level season doesn't have critic_ratings")
|
||||
elif self.name.startswith("text(audience") and self.level == "season":
|
||||
raise Failed("Overlay Error: builder_level season doesn't have audience_ratings")
|
||||
elif self.name in ["text(season_episode)", "text(show_title)"] and self.level not in ["season", "episode"]:
|
||||
raise Failed(f"Overlay Error: {self.name[5:-1]} only works with builder_level season and episode")
|
||||
elif self.name == "text(runtime)" and self.level not in ["movie", "episode"]:
|
||||
raise Failed("Overlay Error: runtime only works with movies and builder_level: episode")
|
||||
elif self.name == "text(season_title)" and self.level != "episode":
|
||||
raise Failed("Overlay Error: season_title only works with builder_level: episode")
|
||||
elif self.name == "text(original_title)" and self.level not in ["movie", "show"]:
|
||||
raise Failed("Overlay Error: original_title only works with movies and shows")
|
||||
elif self.name == "text(episode_count)" and self.level not in ["show", "season"]:
|
||||
raise Failed("Overlay Error: episode_count only works with shows and builder_level: season")
|
||||
elif self.name == ["text(content_rating)", "text(originally_available)"] and self.level == "season":
|
||||
raise Failed(f"Overlay Error: {self.name[5:-1]} only works with movies, shows, and builder_level: episode")
|
||||
elif self.name in old_special_text:
|
||||
self.text_overlay_format = "<<value#>>" if self.name[-2] == "#" else f"<<value%>>{'' if self.name[-2] == '0' else '%'}"
|
||||
self.name = f"{self.name[:-2]})"
|
||||
elif "text_format" in self.data and self.data["text_format"]:
|
||||
if self.name in rating_special_text and not any((f"<<value{m}>>" in self.data["text_format"] for m in ["", "#", "%"])):
|
||||
raise Failed("Overlay Error: text_format must have the value variable")
|
||||
elif self.name == "text(season_episode)" and self.level == "season" and not any((f"<<season{m}>>" in self.data["text_format"] for m in ["", "W", "0", "00"])):
|
||||
raise Failed("Overlay Error: text_format must have the season variable")
|
||||
elif self.name == "text(season_episode)" and self.level == "episode" and not any((f"<<{a}{m}>>" in self.data["text_format"] for a in ["season", "episode"] for m in ["", "W", "0", "00"])):
|
||||
raise Failed("Overlay Error: text_format must have the season or episode variable")
|
||||
elif self.name == "text(runtime)" and not any((f"<<value{m}>>" in self.data["text_format"] for m in ["", "M", "H"])):
|
||||
raise Failed("Overlay Error: text_format must have the value variable")
|
||||
elif self.name == "text(originally_available)":
|
||||
match = re.search("<<value\\[(.+)]>>", self.data["text_format"])
|
||||
if not match and "<<value>>" not in self.data["text_format"]:
|
||||
raise Failed("Overlay Error: text_format must have the value variable")
|
||||
if text in old_special_text2:
|
||||
text_mod = text[-1] if text[-1] in ["0", "%", "#"] else None
|
||||
text = text if text_mod is None else text[:-1]
|
||||
self.special_text = f"<<{text}#>>" if text_mod == "#" else f"<<{text}%>>{'' if text_mod == '0' else '%'}"
|
||||
self.name = "text(special_text)"
|
||||
elif self.name == "text(special_text)":
|
||||
if "special_text" not in self.data or not self.data["special_text"]:
|
||||
raise Failed("Overlay Error: text(special_text) requires the special_text attribute")
|
||||
if "<<originally_available[" in self.data["special_text"]:
|
||||
match = re.search("<<originally_available\\[(.+)]>>", self.data["special_text"])
|
||||
if match:
|
||||
try:
|
||||
datetime.now().strftime(match.group(1))
|
||||
except ValueError:
|
||||
raise Failed("Overlay Error: text_format date format not valid")
|
||||
elif self.name[5:-1] in value_overlays and "<<value>>" not in self.data["text_format"]:
|
||||
raise Failed("Overlay Error: text_format must have the value variable")
|
||||
self.text_overlay_format = self.data["text_format"]
|
||||
elif self.name == "text(season_episode)":
|
||||
self.text_overlay_format = "S<<season0>>" if self.level == "season" else "S<<season0>>E<<episode0>>"
|
||||
else:
|
||||
self.text_overlay_format = "<<value>>"
|
||||
raise Failed("Overlay Error: originally_available date format not valid")
|
||||
self.special_text = self.data["special_text"]
|
||||
|
||||
else:
|
||||
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])
|
||||
|
@ -430,7 +433,7 @@ class Overlay:
|
|||
output += f"{self.back_box[0]}{self.back_box[1]}{self.back_align}"
|
||||
if self.addon_position is not None:
|
||||
output += f"{self.addon_position}{self.addon_offset}"
|
||||
for value in [self.font_color, self.back_color, self.back_radius, self.back_padding, self.back_line_color, self.back_line_width, self.text_overlay_format]:
|
||||
for value in [self.font_color, self.back_color, self.back_radius, self.back_padding, self.back_line_color, self.back_line_width, self.special_text]:
|
||||
if value is not None:
|
||||
output += f"{value}"
|
||||
return output
|
||||
|
|
|
@ -120,17 +120,21 @@ class Overlays:
|
|||
if self.config.Cache:
|
||||
for over_name in over_names:
|
||||
current_overlay = properties[over_name]
|
||||
if current_overlay.name in overlay.special_text_overlays:
|
||||
data_type = current_overlay.name[5:-1]
|
||||
actual = plex.attribute_translation[data_type] if data_type in plex.attribute_translation[data_type] else data_type
|
||||
cache_value = self.config.Cache.query_overlay_special_text(item.ratingKey, data_type)
|
||||
if current_overlay.name == "text(special_text)":
|
||||
for cache_key, cache_value in self.config.Cache.query_overlay_special_text(item.ratingKey).items():
|
||||
actual = plex.attribute_translation[cache_key] if cache_key in plex.attribute_translation[cache_key] else cache_key
|
||||
if cache_value is None or not hasattr(item, actual) or getattr(item, actual) is None:
|
||||
continue
|
||||
if current_overlay.name in overlay.rating_special_text:
|
||||
if cache_key in overlay.float_vars:
|
||||
cache_value = float(cache_value)
|
||||
if getattr(item, actual) != cache_value:
|
||||
overlay_change = True
|
||||
if cache_key in overlay.int_vars:
|
||||
cache_value = int(cache_value)
|
||||
|
||||
if cache_key in overlay.date_vars:
|
||||
if getattr(item, actual).strftime("%Y-%m-%d") != cache_value:
|
||||
overlay_change = True
|
||||
elif getattr(item, actual) != cache_value:
|
||||
overlay_change = True
|
||||
try:
|
||||
poster, background, item_dir, name = self.library.find_item_assets(item)
|
||||
if not poster and self.library.assets_for_all:
|
||||
|
@ -199,64 +203,71 @@ class Overlays:
|
|||
|
||||
def get_text(text_overlay):
|
||||
full_text = text_overlay.name[5:-1]
|
||||
if text_overlay.name in overlay.special_text_overlays:
|
||||
if full_text == "season_episode" and text_overlay.level == "season":
|
||||
actual_attr = "seasonNumber"
|
||||
elif full_text == "show_title":
|
||||
actual_attr = "parentTitle" if text_overlay.level == "season" else "grandparentTitle"
|
||||
elif full_text in plex.attribute_translation:
|
||||
actual_attr = plex.attribute_translation[full_text]
|
||||
if full_text == "special_text":
|
||||
full_text = text_overlay.special_text
|
||||
for format_var in overlay.vars_by_type[text_overlay.level]:
|
||||
if f"<<{format_var}" in full_text and format_var == "originally_available[":
|
||||
mod = re.search("<<originally_available\\[(.+)]>>", full_text).group(1)
|
||||
format_var = "originally_available"
|
||||
elif f"<<{format_var}>>" in full_text and format_var.endswith("00"):
|
||||
mod = "00"
|
||||
format_var = format_var[:-2]
|
||||
elif f"<<{format_var}>>" in full_text and format_var.endswith(("%", "#", "H", "M", "0")):
|
||||
mod = format_var[-1]
|
||||
format_var = format_var[:-1]
|
||||
elif f"<<{format_var}>>" in full_text:
|
||||
mod = ""
|
||||
else:
|
||||
actual_attr = full_text
|
||||
continue
|
||||
if format_var == "show_title":
|
||||
actual_attr = "parentTitle" if text_overlay.level == "season" else "grandparentTitle"
|
||||
elif format_var in plex.attribute_translation:
|
||||
actual_attr = plex.attribute_translation[format_var]
|
||||
else:
|
||||
actual_attr = format_var
|
||||
if not hasattr(item, actual_attr) or getattr(item, actual_attr) is None:
|
||||
raise Failed(f"Overlay Warning: No {full_text} found")
|
||||
logger.warning(f"Overlay Warning: No {full_text} found")
|
||||
continue
|
||||
actual_value = getattr(item, actual_attr)
|
||||
if self.config.Cache:
|
||||
self.config.Cache.update_overlay_special_text(item.ratingKey, full_text, actual_value)
|
||||
full_text = str(text_overlay.text_overlay_format)
|
||||
if text_overlay.name in overlay.value_overlays + overlay.rating_special_text + ["text(originally_available)"] and "<<value>>" in full_text:
|
||||
full_text = full_text.replace("<<value>>", actual_value)
|
||||
if text_overlay.name in overlay.rating_special_text:
|
||||
if "<<value%>>" in full_text:
|
||||
full_text = full_text.replace("<<value%>>", f"{int(actual_value * 10)}%")
|
||||
if "<<value0>>" in full_text:
|
||||
full_text = full_text.replace("<<value0>>", f"{int(actual_value * 10)}")
|
||||
if "<<value#>>" in full_text:
|
||||
full_text = full_text.replace("<<value#>>", str(actual_value)[:-2] if str(actual_value).endswith(".0") else actual_value)
|
||||
elif text_overlay.name == "text(originally_available)":
|
||||
if "<<value>>" in full_text:
|
||||
full_text = full_text.replace("<<value>>", actual_value.strftime("%Y-%m-%d"))
|
||||
match = re.search("<<value\\[(.+)]>>", full_text)
|
||||
if match:
|
||||
full_text = re.sub("<<value\\[(.+)]>>", str(actual_value.strftime(match.group(1))), full_text)
|
||||
elif text_overlay.name == "text(runtime)":
|
||||
if "<<value>>" in full_text:
|
||||
full_text = full_text.replace("<<value>>", actual_value / 60000)
|
||||
if "<<valueH>>" in full_text:
|
||||
full_text = full_text.replace("<<valueH>>", (actual_value / 60000) // 60)
|
||||
if "<<valueM>>" in full_text:
|
||||
full_text = full_text.replace("<<valueM>>", (actual_value / 60000) % 60)
|
||||
elif text_overlay.name == "text(season_episode)":
|
||||
if text_overlay.level == "season":
|
||||
season = actual_value
|
||||
episode = None
|
||||
cache_store = actual_value.strftime("%Y-%m-%d") if format_var in overlay.date_vars else actual_value
|
||||
self.config.Cache.update_overlay_special_text(item.ratingKey, format_var, cache_store)
|
||||
sub_value = None
|
||||
if format_var == "originally_available":
|
||||
if mod:
|
||||
sub_value = "<<originally_available\\[(.+)]>>"
|
||||
final_value = actual_value.strftime(mod)
|
||||
else:
|
||||
season, episode = actual_value.upper()[1:].split("E")
|
||||
for attr, attr_val in [("season", season), ("episode", episode)]:
|
||||
if attr_val and f"<<{attr}>>" in full_text:
|
||||
full_text = full_text.replace(f"<<{attr}>>", attr_val)
|
||||
if attr_val and f"<<{attr}W>>" in full_text:
|
||||
full_text = full_text.replace(f"<<{attr}W>>", num2words(int(attr_val)))
|
||||
if attr_val and f"<<{attr}0>>" in full_text:
|
||||
full_text = full_text.replace(f"<<{attr}0>>", f"{int(attr_val):02}")
|
||||
if attr_val and f"<<{attr}00>>" in full_text:
|
||||
full_text = full_text.replace(f"<<{attr}00>>", f"{int(attr_val):03}")
|
||||
final_value = actual_value.strftime("%Y-%m-%d")
|
||||
elif format_var == "runtime":
|
||||
if mod == "H":
|
||||
final_value = (actual_value / 60000) // 60
|
||||
elif mod == "M":
|
||||
final_value = (actual_value / 60000) % 60
|
||||
else:
|
||||
final_value = actual_value / 60000
|
||||
elif mod == "%":
|
||||
final_value = int(actual_value * 10)
|
||||
elif mod == "#":
|
||||
final_value = str(actual_value)[:-2] if str(actual_value).endswith(".0") else actual_value
|
||||
elif mod == "W":
|
||||
final_value = num2words(int(actual_value))
|
||||
elif mod == "0":
|
||||
final_value = f"{int(actual_value):02}"
|
||||
elif mod == "00":
|
||||
final_value = f"{int(actual_value):03}"
|
||||
else:
|
||||
final_value = actual_value
|
||||
if sub_value:
|
||||
full_text = re.sub(sub_value, str(final_value), full_text)
|
||||
else:
|
||||
full_text = full_text.replace(f"<<{format_var}{mod}>>", str(final_value))
|
||||
return str(full_text)
|
||||
|
||||
for over_name in applied_names:
|
||||
current_overlay = properties[over_name]
|
||||
if current_overlay.name.startswith("text"):
|
||||
if current_overlay.name in overlay.special_text_overlays:
|
||||
if current_overlay.name == "text(special_text)":
|
||||
image_box = current_overlay.image.size if current_overlay.image else None
|
||||
try:
|
||||
overlay_image, addon_box = current_overlay.get_backdrop((canvas_width, canvas_height), box=image_box, text=get_text(current_overlay))
|
||||
|
|
|
@ -148,9 +148,8 @@ attribute_translation = {
|
|||
"writer": "writers",
|
||||
"mood": "moods",
|
||||
"style": "styles",
|
||||
"season_episode": "seasonEpisode",
|
||||
"episode": "episodeNumber",
|
||||
"season": "seasonNumber",
|
||||
"episode_number": "episodeNumber",
|
||||
"season_number": "seasonNumber",
|
||||
"original_title": "originalTitle",
|
||||
"runtime": "duration",
|
||||
"season_title": "parentTitle",
|
||||
|
|
Loading…
Reference in a new issue