Forked from JonnyWong16/select_tmdb_poster.py
Last active
September 15, 2024 22:40
-
-
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).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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