Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,114 @@
|
|||||||
|
# Overlay Files
|
||||||
|
|
||||||
|
Overlay files are used to create and maintain overlays within the Plex libraries on the server.
|
||||||
|
|
||||||
|
Overlays and templates are defined within one or more Overlay files, which are linked to libraries in the [Libraries Attribute](../config/libraries.md#overlay-path) within the [Configuration File](../config/configuration.md).
|
||||||
|
|
||||||
|
**To remove all overlays use the `remove_overlays` library operation.**
|
||||||
|
|
||||||
|
**To change a single overlay original Image either replace the image in the assets folder or remove the `Overlay` shared label and then PMM will overlay the new image**
|
||||||
|
|
||||||
|
These are the attributes which can be used within the Overlay File:
|
||||||
|
|
||||||
|
| Attribute | Description |
|
||||||
|
|:--------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| [`templates`](templates) | contains definitions of templates that can be leveraged by multiple overlays |
|
||||||
|
| [`external_templates`](templates.md#external-templates) | contains [path types](../config/paths) that point to external templates that can be leveraged by multiple overlays |
|
||||||
|
| [`overlays`](#overlay-attributes) | contains definitions of overlays you wish to add |
|
||||||
|
|
||||||
|
* `overlays` is required in order to run the Overlay File.
|
||||||
|
* Example Overlay Files can be found in the [Plex Meta Manager Configs Repository](https://github.com/meisnate12/Plex-Meta-Manager-Configs/tree/master/PMM)
|
||||||
|
|
||||||
|
## Overlay Attributes
|
||||||
|
|
||||||
|
Each overlay requires its own section within the `overalys` attribute.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
overlays:
|
||||||
|
IMDb Top 250:
|
||||||
|
# ... builders, details, and filters for this overlay
|
||||||
|
4K:
|
||||||
|
# ... builders, details, and filters for this overlay
|
||||||
|
etc:
|
||||||
|
# ... builders, details, and filters for this overlay
|
||||||
|
```
|
||||||
|
|
||||||
|
Each section must have the only required attribute, `overlay`.
|
||||||
|
|
||||||
|
|
||||||
|
| Attribute | Description | Required |
|
||||||
|
|:----------|:-------------------------------------------------------------------------------------------------------------|:--------:|
|
||||||
|
| `name` | Name of the overlay. Each overlay name should be unique. | ✅ |
|
||||||
|
| `url` | URL of Overlay Image Online | ❌ |
|
||||||
|
| `git` | Location in the [Configs Repo](https://github.com/meisnate12/Plex-Meta-Manager-Configs) of the Overlay Image | ❌ |
|
||||||
|
| `repo` | Location in the [Custom Repo](../config/settings.md#custom-repo) of the Overlay Image | ❌ |
|
||||||
|
|
||||||
|
* If `url`, `git`, and `repo` are all not defined then PMM will look in your `config/overlays` folder for a `.png` file named the same as the `name` attribute.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
overlays:
|
||||||
|
IMDb Top 250:
|
||||||
|
overlay:
|
||||||
|
name: IMDb Top 250
|
||||||
|
imdb_chart: top_movies
|
||||||
|
```
|
||||||
|
|
||||||
|
There are three types of attributes that can be utilized within an overlay:
|
||||||
|
|
||||||
|
### Builders
|
||||||
|
|
||||||
|
Builders use third-party services to source items for overlays. Multiple builders can be used in the same overlay from a variety of sources listed below.
|
||||||
|
|
||||||
|
* [Plex Builders](builders/plex)
|
||||||
|
* [Smart Builders](builders/smart)
|
||||||
|
* [TMDb Builders](builders/tmdb)
|
||||||
|
* [TVDb Builders](builders/tvdb)
|
||||||
|
* [IMDb Builders](builders/imdb)
|
||||||
|
* [Trakt Builders](builders/trakt)
|
||||||
|
* [Tautulli Builders](builders/tautulli)
|
||||||
|
* [Letterboxd Builders](builders/letterboxd)
|
||||||
|
* [ICheckMovies Builders](builders/icheckmovies)
|
||||||
|
* [FlixPatrol Builders](builders/flixpatrol)
|
||||||
|
* [StevenLu Builders](builders/stevenlu)
|
||||||
|
* [AniDB Builders](builders/anidb)
|
||||||
|
* [AniList Builders](builders/anilist)
|
||||||
|
* [MyAnimeList Builders](builders/myanimelist)
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
Only a few details can be used with overlays: `limit`, `show_missing`, `save_missing`, `missing_only_released`, `minimum_items`, `cache_builders`, `tmdb_region`
|
||||||
|
|
||||||
|
* [Setting Details](details/setting)
|
||||||
|
* [Metadata Details](details/metadata)
|
||||||
|
|
||||||
|
## Filters
|
||||||
|
|
||||||
|
These filter media items added to the collection by any of the Builders.
|
||||||
|
|
||||||
|
* [Filters](filters)
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
overlays:
|
||||||
|
4K:
|
||||||
|
overlay:
|
||||||
|
name: 4K # This will look for a local overlays/4K.png in your configs folder
|
||||||
|
plex_search:
|
||||||
|
all:
|
||||||
|
resolution: 4K
|
||||||
|
HDR:
|
||||||
|
overlay:
|
||||||
|
name: HDR
|
||||||
|
git: PMM/overlays/HDR
|
||||||
|
plex_search:
|
||||||
|
all:
|
||||||
|
hdr: true
|
||||||
|
Dolby:
|
||||||
|
overlay:
|
||||||
|
name: Dolby
|
||||||
|
url: https://somewebsite.com/dobly_overlay.png
|
||||||
|
plex_all: true
|
||||||
|
filters:
|
||||||
|
has_dolby_vision: true
|
||||||
|
```
|
@ -0,0 +1,94 @@
|
|||||||
|
# Playlist Files
|
||||||
|
|
||||||
|
Playlist files are used to create and maintain playlists on the Plex Server.
|
||||||
|
|
||||||
|
If utilized to their fullest, these files can be used to maintain the entire server's collections and playlists, and can be used as a backup for these in the event of a restore requirement.
|
||||||
|
|
||||||
|
Playlists are defined in one or more Playlist files that are mapped in the [Playlist Files Attribute](../config/libraries.md#playlist-files-attribute) within the Configuration File.
|
||||||
|
|
||||||
|
These are the attributes which can be utilized within the Playlist File:
|
||||||
|
|
||||||
|
| Attribute | Description |
|
||||||
|
|:--------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| [`templates`](templates) | contains definitions of templates that can be leveraged by multiple playlists |
|
||||||
|
| [`external_templates`](templates.md#external-templates) | contains [path types](../config/paths) that point to external templates that can be leveraged by multiple playlists |
|
||||||
|
| [`playlists`](#playlist-attributes) | contains definitions of playlists you wish to add to the server |
|
||||||
|
|
||||||
|
* `playlists` is required in order to run the Playlist File.
|
||||||
|
* You can find example Playlist Files in the [Plex Meta Manager Configs Repository](https://github.com/meisnate12/Plex-Meta-Manager-Configs/tree/master/PMM)
|
||||||
|
* Plex does not support the "Continue Watching" feature for playlists, you can [vote for the feature here](https://forums.plex.tv/t/playlists-remember-position-for-subsequent-resume/84866/39)
|
||||||
|
|
||||||
|
## Playlist Attributes
|
||||||
|
|
||||||
|
Plex Meta Manager can automatically build and update playlists defined within the `playlists` attribute.
|
||||||
|
|
||||||
|
Each playlist requires its own section within the `playlists` attribute and unlike collections, playlists can only be built using one Builder as their ordering is inherited from the builder; it is not possible to combine builders.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
playlists:
|
||||||
|
Marvel Cinematic Universe Chronological Order:
|
||||||
|
# ... builder, details, and filters for this playlist
|
||||||
|
Star Wars Clone Wars Chronological Order:
|
||||||
|
# ... builder, details, and filters for this playlist
|
||||||
|
etc:
|
||||||
|
# ... builder, details, and filters for this playlist
|
||||||
|
```
|
||||||
|
|
||||||
|
Playlists require the `libraries` attribute, which instructs the operation to look in the specified libraries. This allows media to be combined from multiple libraries into one playlist. The mappings that you define in the `libraries` attribute must match the library names in your [Configuration File](../config/configuration).
|
||||||
|
|
||||||
|
The playlist can also use the `sync_to_users` attributes to control who has visibility of the playlist. This will override the global [`playlist_sync_to_users` Setting](../config/settings.md#playlist-sync-to-users). `sync_to_users` can be set to `all` to sync to all users who have access to the Plex Media Server, or a list/comma-separated string of users. The Plex Media Server owner will always have visibility of the Playlists, so does not need to be defined within the attribute. Leaving `sync_to_users` empty will make the playlist visible to the Plex Media Server owner only.
|
||||||
|
|
||||||
|
There are three types of attributes that can be utilized within a playlist:
|
||||||
|
|
||||||
|
### Builders
|
||||||
|
|
||||||
|
Builders use third-party services to source items to be added to the playlist. Multiple builders can be used in the same playlist from a variety of sources listed below.
|
||||||
|
|
||||||
|
* [Plex Builders](builders/plex)
|
||||||
|
* [Smart Builders](builders/smart)
|
||||||
|
* [TMDb Builders](builders/tmdb)
|
||||||
|
* [TVDb Builders](builders/tvdb)
|
||||||
|
* [IMDb Builders](builders/imdb)
|
||||||
|
* [Trakt Builders](builders/trakt)
|
||||||
|
* [Tautulli Builders](builders/tautulli)
|
||||||
|
* [Letterboxd Builders](builders/letterboxd)
|
||||||
|
* [ICheckMovies Builders](builders/icheckmovies)
|
||||||
|
* [FlixPatrol Builders](builders/flixpatrol)
|
||||||
|
* [StevenLu Builders](builders/stevenlu)
|
||||||
|
* [AniDB Builders](builders/anidb)
|
||||||
|
* [AniList Builders](builders/anilist)
|
||||||
|
* [MyAnimeList Builders](builders/myanimelist)
|
||||||
|
|
||||||
|
### Details
|
||||||
|
|
||||||
|
These can alter any aspect of the playlist or the media items within them.
|
||||||
|
|
||||||
|
* [Setting Details](details/setting)
|
||||||
|
* [Schedule Detail](details/schedule)
|
||||||
|
* [Metadata Details](details/metadata)
|
||||||
|
* [Arr Details](details/arr)
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
These filter media items added to the playlist by any of the Builders.
|
||||||
|
|
||||||
|
* [Filters](filters)
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
In the following example, media is pulled from the `Movies` and `TV Shows` libraries into the one Playlist, and the playlist is shared with a specific set of users:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
playlists:
|
||||||
|
Marvel Cinematic Universe Chronological Order:
|
||||||
|
sync_mode: sync
|
||||||
|
libraries: Movies, TV Shows
|
||||||
|
sync_to_users: User1, someone@somewhere.com, User3
|
||||||
|
trakt_list: https://trakt.tv/users/donxy/lists/marvel-cinematic-universe?sort=rank,asc
|
||||||
|
summary: Marvel Cinematic Universe In Chronological Order
|
||||||
|
Star Wars Clone Wars Chronological Order:
|
||||||
|
sync_to_users: all
|
||||||
|
sync_mode: sync
|
||||||
|
libraries: Movies, TV Shows
|
||||||
|
trakt_list: https://trakt.tv/users/tomfin46/lists/star-wars-the-clone-wars-chronological-episode-order
|
||||||
|
```
|
@ -0,0 +1,203 @@
|
|||||||
|
import os, time
|
||||||
|
from modules import util
|
||||||
|
from modules.builder import CollectionBuilder
|
||||||
|
from modules.util import Failed
|
||||||
|
from plexapi.exceptions import BadRequest
|
||||||
|
from plexapi.video import Show, Season, Episode
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
logger = util.logger
|
||||||
|
|
||||||
|
class Overlays:
|
||||||
|
def __init__(self, config, library):
|
||||||
|
self.config = config
|
||||||
|
self.library = library
|
||||||
|
self.overlays = []
|
||||||
|
|
||||||
|
def run_overlays(self):
|
||||||
|
logger.info("")
|
||||||
|
logger.separator(f"{self.library.name} Library Overlays")
|
||||||
|
logger.info("")
|
||||||
|
overlay_rating_keys = {}
|
||||||
|
item_keys = {}
|
||||||
|
os.makedirs(self.library.overlay_backup, exist_ok=True)
|
||||||
|
overlay_updated = {}
|
||||||
|
overlay_images = {}
|
||||||
|
item_overlays = {}
|
||||||
|
if not self.library.remove_overlays:
|
||||||
|
for overlay_file in self.library.overlay_files:
|
||||||
|
for k, v in overlay_file.overlays.items():
|
||||||
|
builder = CollectionBuilder(self.config, overlay_file, k, v, library=self.library, overlay=True)
|
||||||
|
logger.info("")
|
||||||
|
|
||||||
|
logger.separator(f"Running {k} Overlay", space=False, border=False)
|
||||||
|
|
||||||
|
if builder.filters or builder.tmdb_filters:
|
||||||
|
logger.info("")
|
||||||
|
for filter_key, filter_value in builder.filters:
|
||||||
|
logger.info(f"Collection Filter {filter_key}: {filter_value}")
|
||||||
|
for filter_key, filter_value in builder.tmdb_filters:
|
||||||
|
logger.info(f"Collection Filter {filter_key}: {filter_value}")
|
||||||
|
|
||||||
|
for method, value in builder.builders:
|
||||||
|
logger.debug("")
|
||||||
|
logger.debug(f"Builder: {method}: {value}")
|
||||||
|
logger.info("")
|
||||||
|
builder.filter_and_save_items(builder.gather_ids(method, value))
|
||||||
|
if builder.added_items:
|
||||||
|
if builder.overlay not in overlay_rating_keys:
|
||||||
|
overlay_rating_keys[builder.overlay] = []
|
||||||
|
for item in builder.added_items:
|
||||||
|
item_keys[item.ratingKey] = item
|
||||||
|
if item.ratingKey not in overlay_rating_keys[builder.overlay]:
|
||||||
|
overlay_rating_keys[builder.overlay].append(item.ratingKey)
|
||||||
|
|
||||||
|
for overlay_name, over_keys in overlay_rating_keys.items():
|
||||||
|
clean_name, _ = util.validate_filename(overlay_name)
|
||||||
|
image_compare = None
|
||||||
|
if self.config.Cache:
|
||||||
|
_, image_compare, _ = self.config.Cache.query_image_map(overlay_name, f"{self.library.image_table_name}_overlays")
|
||||||
|
overlay_file = os.path.join(self.library.overlay_folder, f"{clean_name}.png")
|
||||||
|
overlay_size = os.stat(overlay_file).st_size
|
||||||
|
overlay_updated[overlay_name] = not image_compare or str(overlay_size) != str(image_compare)
|
||||||
|
overlay_images[overlay_name] = Image.open(overlay_file).convert("RGBA")
|
||||||
|
for over_key in over_keys:
|
||||||
|
if over_key not in item_overlays:
|
||||||
|
item_overlays[over_key] = []
|
||||||
|
item_overlays[over_key].append(overlay_name)
|
||||||
|
if self.config.Cache:
|
||||||
|
self.config.Cache.update_image_map(overlay_name, f"{self.library.image_table_name}_overlays", overlay_name, overlay_size)
|
||||||
|
|
||||||
|
def get_overlay_items(libtype=None):
|
||||||
|
return [o for o in self.library.search(label="Overlay", libtype=libtype) if o.ratingKey not in item_overlays]
|
||||||
|
|
||||||
|
remove_overlays = get_overlay_items()
|
||||||
|
if self.library.is_show:
|
||||||
|
remove_overlays.extend(get_overlay_items(libtype="episode"))
|
||||||
|
remove_overlays.extend(get_overlay_items(libtype="season"))
|
||||||
|
elif self.library.is_music:
|
||||||
|
remove_overlays.extend(get_overlay_items(libtype="album"))
|
||||||
|
|
||||||
|
for i, item in enumerate(remove_overlays, 1):
|
||||||
|
logger.ghost(f"Restoring: {i}/{len(remove_overlays)} {item.title}")
|
||||||
|
clean_name, _ = util.validate_filename(item.title)
|
||||||
|
poster, _, item_dir = self.library.find_assets(
|
||||||
|
name="poster" if self.library.asset_folders else clean_name,
|
||||||
|
folder_name=clean_name if self.library.asset_folders else None,
|
||||||
|
prefix=f"{item.title}'s "
|
||||||
|
)
|
||||||
|
poster_location = None
|
||||||
|
is_url = False
|
||||||
|
if poster:
|
||||||
|
poster_location = poster.location
|
||||||
|
elif os.path.exists(os.path.join(self.library.overlay_backup, f"{item.ratingKey}.png")):
|
||||||
|
poster_location = os.path.join(self.library.overlay_backup, f"{item.ratingKey}.png")
|
||||||
|
elif os.path.exists(os.path.join(self.library.overlay_backup, f"{item.ratingKey}.jpg")):
|
||||||
|
poster_location = os.path.join(self.library.overlay_backup, f"{item.ratingKey}.jpg")
|
||||||
|
else:
|
||||||
|
is_url = True
|
||||||
|
if self.library.is_movie:
|
||||||
|
if item.ratingKey in self.library.movie_rating_key_map:
|
||||||
|
poster_location = self.config.TMDb.get_movie(self.library.movie_rating_key_map[item.ratingKey]).poster_url
|
||||||
|
elif self.library.is_show:
|
||||||
|
if item.ratingKey in self.library.show_rating_key_map:
|
||||||
|
poster_location = self.config.TMDb.get_show(self.config.Convert.tvdb_to_tmdb(self.library.show_rating_key_map[item.ratingKey])).poster_url
|
||||||
|
if poster_location:
|
||||||
|
self.library.upload_poster(item, poster_location, url=is_url)
|
||||||
|
self.library.edit_tags("label", item, remove_tags=["Overlay"])
|
||||||
|
else:
|
||||||
|
logger.error(f"No Poster found to restore for {item.title}")
|
||||||
|
logger.exorcise()
|
||||||
|
|
||||||
|
for i, (over_key, over_names) in enumerate(item_overlays.items(), 1):
|
||||||
|
try:
|
||||||
|
item = item_keys[over_key]
|
||||||
|
logger.ghost(f"Overlaying: {i}/{len(item_overlays)} {item.title}")
|
||||||
|
image_compare = None
|
||||||
|
overlay_compare = None
|
||||||
|
if self.config.Cache:
|
||||||
|
image, image_compare, _ = self.config.Cache.query_image_map(item.ratingKey, f"{self.library.image_table_name}_overlays")
|
||||||
|
overlay_compare = [] if overlay_compare is None else util.get_list(overlay_compare)
|
||||||
|
has_overlay = any([item_tag.tag.lower() == "overlay" for item_tag in item.labels])
|
||||||
|
|
||||||
|
overlay_change = False if has_overlay else True
|
||||||
|
if not overlay_change:
|
||||||
|
for oc in overlay_compare:
|
||||||
|
if oc not in over_names:
|
||||||
|
overlay_change = True
|
||||||
|
if not overlay_change:
|
||||||
|
for over_name in over_names:
|
||||||
|
if over_name not in overlay_compare or overlay_updated[over_name]:
|
||||||
|
overlay_change = True
|
||||||
|
|
||||||
|
clean_name, _ = util.validate_filename(item.title)
|
||||||
|
poster, _, item_dir = self.library.find_assets(
|
||||||
|
name="poster" if self.library.asset_folders else clean_name,
|
||||||
|
folder_name=clean_name if self.library.asset_folders else None,
|
||||||
|
prefix=f"{item.title}'s "
|
||||||
|
)
|
||||||
|
has_original = False
|
||||||
|
changed_image = False
|
||||||
|
if poster:
|
||||||
|
if image_compare and str(poster.compare) != str(image_compare):
|
||||||
|
changed_image = True
|
||||||
|
else:
|
||||||
|
if os.path.exists(os.path.join(self.library.overlay_backup, f"{item.ratingKey}.png")):
|
||||||
|
has_original = os.path.join(self.library.overlay_backup, f"{item.ratingKey}.png")
|
||||||
|
elif os.path.exists(os.path.join(self.library.overlay_backup, f"{item.ratingKey}.jpg")):
|
||||||
|
has_original = os.path.join(self.library.overlay_backup, f"{item.ratingKey}.jpg")
|
||||||
|
else:
|
||||||
|
changed_image = True
|
||||||
|
self.library.reload(item)
|
||||||
|
poster_url = item.posterUrl
|
||||||
|
if has_overlay:
|
||||||
|
if self.library.is_movie:
|
||||||
|
if item.ratingKey in self.library.movie_rating_key_map:
|
||||||
|
poster_url = self.config.TMDb.get_movie(self.library.movie_rating_key_map[item.ratingKey]).poster_url
|
||||||
|
elif self.library.is_show:
|
||||||
|
check_key = item.ratingKey if isinstance(item, Show) else item.show().ratingKey
|
||||||
|
tmdb_id = self.config.Convert.tvdb_to_tmdb(self.library.show_rating_key_map[check_key])
|
||||||
|
if isinstance(item, Show) and item.ratingKey in self.library.show_rating_key_map:
|
||||||
|
poster_url = self.config.TMDb.get_show(tmdb_id).poster_url
|
||||||
|
elif isinstance(item, Season):
|
||||||
|
poster_url = self.config.TMDb.get_season(tmdb_id, item.seasonNumber).poster_url
|
||||||
|
elif isinstance(item, Episode):
|
||||||
|
poster_url = self.config.TMDb.get_episode(tmdb_id, item.seasonNumber, item.episodeNumber).still_url
|
||||||
|
response = self.config.get(poster_url)
|
||||||
|
if response.status_code >= 400:
|
||||||
|
raise Failed(f"Overlay Error: Poster Download Failed for {item.title}")
|
||||||
|
ext = "jpg" if response.headers["Content-Type"] == "image/jpeg" else "png"
|
||||||
|
backup_image = os.path.join(self.library.overlay_backup, f"{item.ratingKey}.{ext}")
|
||||||
|
with open(backup_image, "wb") as handler:
|
||||||
|
handler.write(response.content)
|
||||||
|
while util.is_locked(backup_image):
|
||||||
|
time.sleep(1)
|
||||||
|
has_original = backup_image
|
||||||
|
|
||||||
|
poster_uploaded = False
|
||||||
|
if changed_image or overlay_change:
|
||||||
|
new_poster = Image.open(poster.location if poster else has_original).convert("RGBA")
|
||||||
|
temp = os.path.join(self.library.overlay_folder, f"temp.png")
|
||||||
|
try:
|
||||||
|
for over_name in over_names:
|
||||||
|
new_poster = new_poster.resize(overlay_images[over_name].size, Image.ANTIALIAS)
|
||||||
|
new_poster.paste(overlay_images[over_name], (0, 0), overlay_images[over_name])
|
||||||
|
new_poster.save(temp, "PNG")
|
||||||
|
self.library.upload_poster(item, temp)
|
||||||
|
self.library.edit_tags("label", item, add_tags=["Overlay"])
|
||||||
|
self.library.reload(item)
|
||||||
|
poster_uploaded = True
|
||||||
|
logger.info(f"Detail: Overlays: {', '.join(over_names)} applied to {item.title}")
|
||||||
|
except (OSError, BadRequest) as e:
|
||||||
|
logger.stacktrace()
|
||||||
|
raise Failed(f"Overlay Error: {e}")
|
||||||
|
|
||||||
|
if self.config.Cache:
|
||||||
|
if poster_uploaded:
|
||||||
|
self.config.Cache.update_image_map(
|
||||||
|
item.ratingKey, self.library.image_table_name, item.thumb,
|
||||||
|
poster.compare if poster else item.thumb, overlay=','.join(over_names)
|
||||||
|
)
|
||||||
|
except Failed as e:
|
||||||
|
logger.error(e)
|
||||||
|
logger.exorcise()
|