diff --git a/VERSION b/VERSION
index 2092df01..da0d6250 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.17.2-develop10
+1.17.2-develop11
diff --git a/docs/metadata/overlay.md b/docs/metadata/overlay.md
index 2c6d16f2..4d84636b 100644
--- a/docs/metadata/overlay.md
+++ b/docs/metadata/overlay.md
@@ -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.
**Value:** Integer greater than 0 | ❌ |
| `back_line_color` | Backdrop Line Color for the Text Overlay.
**Value:** Color Hex Code in format `#RGB`, `#RGBA`, `#RRGGBB` or `#RRGGBBAA`. | ❌ |
| `back_line_width` | Backdrop Line Width for the Text Overlay.
**Value:** Integer greater than 0 | ❌ |
-| `text_format` | Text Format for Special Text Overlays.
**`text_format` Only works with text overlays**
**Value:** Integer 0 or greater | ❌ |
+| `special_text` | Text Format for Special Text Overlays.
**`special_text` Only works with text overlays** | ❌ |
| `addon_offset` | Text Addon Image Offset from the text.
**`addon_offset` Only works with text overlays**
**Value:** Integer 0 or greater | ❌ |
| `addon_position` | Text Addon Image Alignment in relation to the text.
**`addon_position` Only works with text overlays**
**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 `<>` and some can have modifiers like so `<>` 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 (`8.7`, `9.0`)
`<>`: audience rating out of 100 (`87`, `90`)
`<>`: audience rating removing `.0` as needed (`8.7`, `9`) | ✅ | ✅ | ❌ | ✅ |
+| critic_rating | `<>`: critic rating (`8.7`, `9.0`)
`<>`: critic rating out of 100 (`87`, `90`)
`<>`: critic rating removing `.0` as needed (`8.7`, `9`) | ✅ | ✅ | ❌ | ✅ |
+| user_rating | `<>`: user rating (`8.7`, `9.0`)
`<>`: user rating out of 100 (`87`, `90`)
`<>`: user rating removing `.0` as needed (`8.7`, `9`) | ✅ | ✅ | ✅ | ✅ |
+| title | `<>`: Title of the Item | ✅ | ✅ | ✅ | ✅ |
+| show_title | `<>`: Title of the Item's Show | ❌ | ❌ | ✅ | ✅ |
+| season_title | `<>`: Title of the Item's Season | ❌ | ❌ | ❌ | ✅ |
+| original_title | `<>`: Original Title of the Item | ✅ | ✅ | ❌ | ❌ |
+| content_rating | `<>`: Content Rating of the Item | ✅ | ✅ | ❌ | ✅ |
+| episode_count | `<>`: Number of Episodes (`1`)
`<`: Number of Episodes As Words (`One`)
`<`: Number of Episodes With 10s Padding (`01`)
`<>`: Number of Episodes With 100s Padding (`001`) | ❌ | ✅ | ✅ | ❌ |
+| season_number | `<>`: Season Number (`1`)
`<`: Season Number As Words (`One`)
`<`: Season Number With 10s Padding (`01`)
`<>`: Season Number With 100s Padding (`001`) | ❌ | ❌ | ✅ | ✅ |
+| episode_number | `<>`: Episode Number (`1`)
`<`: Episode Number As Words (`One`)
`<`: Episode Number With 10s Padding (`01`)
`<>`: Episode Number With 100s Padding (`001`) | ❌ | ❌ | ❌ | ✅ |
+| runtime | `<>`: Runtime of the Item in minutes
`<>`: Hours in runtime of the Item
`<>`: Minutes remaining in the hour in the runtime of the Item | ✅ | ❌ | ❌ | ✅ |
+| originally_available | `<>`: Original Available Date of the Item
`<>`: 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 | `<>` -> ratings (`8.7`, `9.0`)
`<>` -> rating out of 100 (`87`, `90`)
`<>` -> rating removing `.0` as needed (`8.7`, `9`) |
-| text(critic_rating) | Doesnt work with Seasons | `<>` -> ratings (`8.7`, `9.0`)
`<>` -> rating out of 100 (`87`, `90`)
`<>` -> rating removing `.0` as needed (`8.7`, `9`) |
-| text(user_rating) | | `<>` -> ratings (`8.7`, `9.0`)
`<>` -> rating out of 100 (`87`, `90`)
`<>` -> rating removing `.0` as needed (`8.7`, `9`) |
-| text(title) | | `<>` -> Title of the Item |
-| text(show_title) | Doesnt work with Movies and Shows | `<>` -> Title of the Item's Show |
-| text(season_title) | Only works with Episodes | `<>` -> Title of the Item's Season |
-| text(original_title) | Only works with Movies and Shows | `<>` -> Original Title of the Item |
-| text(episode_count) | Only works with Shows and Seasons | `<>` -> Number of Episodes in the Show or Season |
-| text(content_rating) | Doesnt work with Seasons | `<>` -> Content Rating of the Item |
-| text(season_episode) | Only works with Seasons and Episodes | `<>` -> Season Number
`<` -> Season Number With 10s Padding
`<>` -> Season Number With 100s Padding
`<>` -> Episode Number
`<` -> Episode Number With 10s Padding
`<>` -> Episode Number With 100s Padding |
-| text(runtime) | Doesnt work with Shows and Seasons | `<>` -> Runtime of the Item in minutes
`<>` -> Hours in runtime of the Item
`<>` -> Minutes remaining in the hour in the runtime of the Item |
-| text(originally_available) | Doesnt work with Seasons | `<>` -> Original Available Date of the Item
`<>` -> 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: <>%
+ name: text(special_text)
+ special_text: <>%
horizontal_offset: 225
horizontal_align: center
vertical_offset: 15
diff --git a/modules/builder.py b/modules/builder.py
index 4518f75b..b0c44a41 100644
--- a/modules/builder.py
+++ b/modules/builder.py
@@ -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:
diff --git a/modules/cache.py b/modules/cache.py
index 80f5db38..50247df5 100644
--- a/modules/cache.py
+++ b/modules/cache.py
@@ -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()
- if row:
- rating = row["text"]
- return rating
+ cursor.execute("SELECT * FROM overlay_special_text WHERE rating_key = ?", (rating_key, ))
+ for row in cursor.fetchall():
+ if row:
+ 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:
diff --git a/modules/overlay.py b/modules/overlay.py
index 5cc9fa18..ef4b055e 100644
--- a/modules/overlay.py
+++ b/modules/overlay.py
@@ -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 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 "<>", self.data["special_text"])
+ if match:
+ try:
+ datetime.now().strftime(match.group(1))
+ except ValueError:
+ raise Failed("Overlay Error: originally_available date format not valid")
+ self.special_text = self.data["special_text"]
- 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 = "<>" if self.name[-2] == "#" else f"<>{'' 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"<>" 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"<>" 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"<>" 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("<>", self.data["text_format"])
- if not match and "<>" not in self.data["text_format"]:
- raise Failed("Overlay Error: text_format must have the value variable")
- 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 "<>" 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<>" if self.level == "season" else "S<>E<>"
- else:
- self.text_overlay_format = "<>"
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
diff --git a/modules/overlays.py b/modules/overlays.py
index f5a7cd66..d8e6445d 100644
--- a/modules/overlays.py
+++ b/modules/overlays.py
@@ -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 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:
- cache_value = float(cache_value)
- if getattr(item, actual) != cache_value:
- overlay_change = True
-
+ 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 cache_key in overlay.float_vars:
+ cache_value = float(cache_value)
+ 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]
- else:
- actual_attr = full_text
- if not hasattr(item, actual_attr) or getattr(item, actual_attr) is None:
- raise Failed(f"Overlay Warning: No {full_text} found")
- 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 "<>" in full_text:
- full_text = full_text.replace("<>", actual_value)
- if text_overlay.name in overlay.rating_special_text:
- if "<>" in full_text:
- full_text = full_text.replace("<>", f"{int(actual_value * 10)}%")
- if "<>" in full_text:
- full_text = full_text.replace("<>", f"{int(actual_value * 10)}")
- if "<>" in full_text:
- full_text = full_text.replace("<>", str(actual_value)[:-2] if str(actual_value).endswith(".0") else actual_value)
- elif text_overlay.name == "text(originally_available)":
- if "<>" in full_text:
- full_text = full_text.replace("<>", actual_value.strftime("%Y-%m-%d"))
- match = re.search("<>", full_text)
- if match:
- full_text = re.sub("<>", str(actual_value.strftime(match.group(1))), full_text)
- elif text_overlay.name == "text(runtime)":
- if "<>" in full_text:
- full_text = full_text.replace("<>", actual_value / 60000)
- if "<>" in full_text:
- full_text = full_text.replace("<>", (actual_value / 60000) // 60)
- if "<>" in full_text:
- full_text = full_text.replace("<>", (actual_value / 60000) % 60)
- elif text_overlay.name == "text(season_episode)":
- if text_overlay.level == "season":
- season = actual_value
- episode = None
+ 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("<>", 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:
+ 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:
+ logger.warning(f"Overlay Warning: No {full_text} found")
+ continue
+ actual_value = getattr(item, actual_attr)
+ if self.config.Cache:
+ 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 = "<>"
+ final_value = actual_value.strftime(mod)
+ else:
+ 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:
- 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}")
+ 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))
diff --git a/modules/plex.py b/modules/plex.py
index 4645da7e..3b527f45 100644
--- a/modules/plex.py
+++ b/modules/plex.py
@@ -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",