Skip to content

Instantly share code, notes, and snippets.

@xenago
Forked from JonnyWong16/select_tmdb_poster.py
Last active March 15, 2024 08:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xenago/f24a5a2d82a0f0060f1794c6c1b76266 to your computer and use it in GitHub Desktop.
Save xenago/f24a5a2d82a0f0060f1794c6c1b76266 to your computer and use it in GitHub Desktop.
Sets the TMDB poster as the default for any movies in a Plex library. Applies to any titles with unlocked posters from Gracenote (or if the poster is unset).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# plex_poster_fix.py
#
# Swaps out posters provided by Gracenote with ones from TMDB.
# Adapted from JonnyWong16's [`select_tmdb_poster.py`](https://gist.github.com/JonnyWong16/b0e6b2761f8649d811f51866e682464b).
# With large libraries, it may take a few seconds up to a minute for the script to start producing output.
# Usage Instructions
#
# Note: usage of a Python venv is optional, but recommended to avoid installing PlexAPI system-wide. See e.g. https://realpython.com/python-virtual-environments-a-primer/
#
# 1. Install Python (method depends on OS)
# * Tested with Python 3.10+
# 2. Download script (example, can use any method to download the file)
# * `wget https://gist.githubusercontent.com/xenago/f24a5a2d82a0f0060f1794c6c1b76266/raw`
# 3. Install PlexAPI library:
# * `pip install PlexAPI==4.15.10`
# * Depending on OS, `pip3` may need to be used as the command instead of `pip`
# 4. Run script:
# * `python plex_poster_fix.py --library "Library Name Here" --plex_url "https://plex-server-ip-here:32400" --plex_token "contents of myPlexAccessToken browser cookie go here"`
# * To increase security, can optionally use the `PLEX_TOKEN` environment variable instead of the `--plex_token` argument
# * Depending on OS, `python3` may need to be used as the command instead of `python`
################################
"""
Description: Selects the default TMDB poster if no poster is selected
or the current poster is from Gracenote.
Author: /u/SwiftPanda16
Requires: plexapi
Usage:
* Provide the Plex server URL, if not using the PLEX_URL environment variable:
python plex_poster_fix.py --plex_url "https://my-plex-url"
* Provide a Plex API key, if not using the PLEX_TOKEN environment variable:
python plex_poster_fix.py --plex_token "my-token-here"
* Change the posters for an entire library:
python plex_poster_fix.py --library "Movies"
* Change the poster for a specific item:
python plex_poster_fix.py --rating_key 1234
* By default locked posters are skipped. To update locked posters:
python plex_poster_fix.py --library "Movies" --include_locked
Tautulli script trigger:
* Notify on recently added
Tautulli script conditions:
* Filter which media to select the poster. Examples:
[ Media Type | is | movie ]
Tautulli script arguments:
* Recently Added:
--rating_key {rating_key}
"""
import argparse
import os
import plexapi.base
from plexapi.server import PlexServer
plexapi.base.USER_DONT_RELOAD_FOR_KEYS.add("fields")
def select_tmdb_poster_library(library, include_locked=False):
for item in library.all(includeGuids=False):
# Only reload for fields
item.reload(**{k: 0 for k, v in item._INCLUDES.items()})
select_tmdb_poster_item(item, include_locked=include_locked)
def select_tmdb_poster_item(item, include_locked=False):
if next((f.locked for f in item.fields if f.name == "thumb"), False) and not include_locked:
print(f"Poster is locked for `{item.title}`. Skipping.")
return
posters = item.posters()
selected_poster = next((p for p in posters if p.selected), None)
item_slug = f"{item.title} ({item.year})"
if selected_poster is None:
print(f"WARNING: No poster selected for `{item_slug}`.")
elif selected_poster.provider == "gracenote":
print(f"WARNING: Poster provider is `gracenote` for `{item_slug}`.")
else:
print(f"Poster provider is `{selected_poster.provider}` for `{item_slug}`. Skipping.")
if selected_poster is None or selected_poster.provider == "gracenote":
# Fallback to first poster if no TMDB posters are available
tmdb_poster = next((p for p in posters if p.provider == "tmdb"), posters[0])
# Selecting the poster automatically locks it
tmdb_poster.select()
print(f"Selected `{tmdb_poster.provider}` poster for `{item_slug}`.")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--plex_url", type=str)
parser.add_argument("--plex_token", type=str)
parser.add_argument("--rating_key", type=int)
parser.add_argument("--library")
parser.add_argument("--include_locked", action="store_true")
opts = parser.parse_args()
# If a token is not provided as a CLI argument, try the environment variable
if opts.plex_url:
PLEX_URL = opts.plex_url
else:
PLEX_URL = os.getenv("PLEX_URL")
if PLEX_URL is None:
print("No Plex URL provided via `--plex_url` argument or `PLEX_URL` environment variable. Exiting.")
exit(1)
if opts.plex_token:
PLEX_TOKEN = opts.plex_token
else:
PLEX_TOKEN = os.getenv("PLEX_TOKEN")
if PLEX_TOKEN is None:
print("No Plex API key provided via `--plex_token` argument or `PLEX_TOKEN` environment variable. Exiting.")
exit(1)
# Attempt to authenticate with the Plex server
plex = PlexServer(PLEX_URL, PLEX_TOKEN)
# Actually perform the poster replacement
if opts.rating_key:
selected_item = plex.fetchItem(opts.rating_key)
select_tmdb_poster_item(selected_item, opts.include_locked)
elif opts.library:
selected_library = plex.library.section(opts.library)
select_tmdb_poster_library(selected_library, opts.include_locked)
else:
print("No `--rating_key` or `--library` specified. Exiting.")
exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment