Skip to content

Instantly share code, notes, and snippets.

@JonnyWong16
Last active April 19, 2025 18:12
Show Gist options
  • Save JonnyWong16/b0e6b2761f8649d811f51866e682464b to your computer and use it in GitHub Desktop.
Save JonnyWong16/b0e6b2761f8649d811f51866e682464b to your computer and use it in GitHub Desktop.
Selects the default TMDB poster and art for items in a Plex library if no poster/art is selected or the current poster/art is from Gracenote.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Description: Selects the default TMDB poster and art for items in a Plex library
if no poster/art is selected or the current poster/art is from Gracenote.
Author: /u/SwiftPanda16
Requires: plexapi
Usage:
* Change the posters for an entire library:
python select_tmdb_poster.py --library "Movies" --poster
* Change the art for an entire library:
python select_tmdb_poster.py --library "Movies" --art
* Change the posters and art for an entire library:
python select_tmdb_poster.py --library "Movies" --poster --art
* Change the poster for a specific item:
python select_tmdb_poster.py --rating_key 1234 --poster
* Change the art for a specific item:
python select_tmdb_poster.py --rating_key 1234 --art
* Change the poster and art for a specific item:
python select_tmdb_poster.py --rating_key 1234 --poster --art
* By default locked posters are skipped. To update locked posters:
python select_tmdb_poster.py --library "Movies" --include_locked --poster --art
* To override the preferred provider:
python select_tmdb_poster.py --library "Movies" --art --art_provider "fanarttv"
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} --poster --art
'''
import argparse
import os
import plexapi.base
from plexapi.server import PlexServer
plexapi.base.USER_DONT_RELOAD_FOR_KEYS.add('fields')
# Poster and art providers to replace
REPLACE_PROVIDERS = ['gracenote', 'plex', None]
# Preferred poster and art provider to use (Note not all providers are availble for all items)
# Possible options: tmdb, tvdb, imdb, fanarttv, gracenote, plex
PREFERRED_POSTER_PROVIDER = 'tmdb'
PREFERRED_ART_PROVIDER = 'tmdb'
# ## OVERRIDES - ONLY EDIT IF RUNNING SCRIPT WITHOUT TAUTULLI ##
PLEX_URL = ''
PLEX_TOKEN = ''
# Environmental Variables
PLEX_URL = PLEX_URL or os.getenv('PLEX_URL', PLEX_URL)
PLEX_TOKEN = PLEX_TOKEN or os.getenv('PLEX_TOKEN', PLEX_TOKEN)
def select_library(
library,
include_locked=False,
poster=False,
poster_provider=PREFERRED_POSTER_PROVIDER,
art=False,
art_provider=PREFERRED_ART_PROVIDER
):
for item in library.all(includeGuids=False):
# Only reload for fields
item.reload(**{k: 0 for k, v in item._INCLUDES.items()})
select_item(
item,
include_locked=include_locked,
poster=poster,
poster_provider=poster_provider,
art=art,
art_provider=art_provider
)
def select_item(
item,
include_locked=False,
poster=False,
poster_provider=PREFERRED_POSTER_PROVIDER,
art=False,
art_provider=PREFERRED_ART_PROVIDER
):
print(f"{item.title} ({item.year})")
if poster:
select_poster(item, include_locked, poster_provider)
if art:
select_art(item, include_locked, art_provider)
def select_poster(item, include_locked=False, provider=PREFERRED_POSTER_PROVIDER):
print(" Checking poster...")
if item.isLocked('thumb') and not include_locked: # PlexAPI 4.5.10
print(f" - Locked poster for {item.title}. Skipping.")
return
posters = item.posters()
selected_poster = next((p for p in posters if p.selected), None)
if selected_poster is None:
print(f" - WARNING: No poster selected for {item.title}.")
else:
skip_poster = selected_poster.provider not in REPLACE_PROVIDERS
print(f" - Poster provider is '{selected_poster.provider}' for {item.title}.")
if posters and (selected_poster is None or selected_poster.provider in REPLACE_PROVIDERS):
# Fallback to first poster if no preferred provider posters are available
provider_poster = next((p for p in posters if p.provider == provider), posters[0])
# Selecting the poster automatically locks it
provider_poster.select()
print(f" - Selected and locked {provider_poster.provider} poster for {item.title}.")
elif skip_poster and selected_poster:
item.lockPoster()
print(f" - Locked {selected_poster.provider} poster for {item.title}.")
def select_art(item, include_locked=False, provider=PREFERRED_ART_PROVIDER):
print(" Checking art...")
if item.isLocked('art') and not include_locked: # PlexAPI 4.5.10
print(f" - Locked art for {item.title}. Skipping.")
return
arts = item.arts()
selected_art = next((p for p in arts if p.selected), None)
if selected_art is None:
print(f" - WARNING: No art selected for {item.title}.")
else:
skip_art = selected_art.provider not in REPLACE_PROVIDERS
print(f" - Art provider is '{selected_art.provider}' for {item.title}.")
if arts and (selected_art is None or selected_art.provider in REPLACE_PROVIDERS):
# Fallback to first art if no preferred provider arts are available
provider_art = next((p for p in arts if p.provider == provider), arts[0])
# Selecting the art automatically locks it
provider_art.select()
print(f" - Selected and locked {provider_art.provider} art for {item.title}.")
elif skip_art and selected_art:
item.lockArt()
print(f" - Locked {selected_art.provider} art for {item.title}.")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--rating_key', type=int)
parser.add_argument('--library')
parser.add_argument('--include_locked', action='store_true')
parser.add_argument('--poster', action='store_true')
parser.add_argument('--poster_provider', default=PREFERRED_POSTER_PROVIDER)
parser.add_argument('--art', action='store_true')
parser.add_argument('--art_provider', default=PREFERRED_ART_PROVIDER)
opts = parser.parse_args()
plex = PlexServer(PLEX_URL, PLEX_TOKEN)
if opts.rating_key:
item = plex.fetchItem(opts.rating_key)
select_item(item, opts.include_locked, opts.poster, opts.poster_provider, opts.art, opts.art_provider)
elif opts.library:
library = plex.library.section(opts.library)
select_library(library, opts.include_locked, opts.poster, opts.poster_provider, opts.art, opts.art_provider)
else:
print("No --rating_key or --library specified. Exiting.")
@thesil3nce
Copy link

Hello, I'm having trouble with the script notifier if you can help. It tries to start, but gives this error after playing
Tautulli Notifiers :: Script returned:     
No --rating_key or --library specified. Exiting.

@Healzangels
Copy link

Greetings!
Thanks for sharing just an awesome script! Has saved me a world of headache.
One thing I have noticed however is when I do a --library "Movies" within Tautulli everything works great, see it processing content however; not sure exactly when but the script will stop running leaving the later half of my collection unchanged.

Wondering if there is away to make sure the script continues to run until everything has been touched or maybe I'm just overlooking something simple. Thanks again

-Cheers!

@shorshiii
Copy link

Hi, this tool has been fantastic for me! thanks a lot!

Is there anything like this for shows?

thank you!

@matijaerceg
Copy link

I just wanna say how much I appreciate this. Thank you. The homemade posters that plex is adding by default now are truly awful.

@baroumas
Copy link

Thank you for providing this script. It's very useful.

@DeadSyncLTU
Copy link

Thank you for very useful script, using it for a while now.
I notices that posters for movies in tmdb website change, not constantly but now and then.
Now script is skipping poster if its already tmdb.
Is it possible to change the script for it to update already selected tmdb poster for the new one that is default at tmdb website?

@JonnyWong16
Copy link
Author

Hi, this tool has been fantastic for me! thanks a lot!

Is there anything like this for shows?

thank you!

@shorshiii There is nothing in this script unique to movies, it also works for tv shows.

Thank you for very useful script, using it for a while now. I notices that posters for movies in tmdb website change, not constantly but now and then. Now script is skipping poster if its already tmdb. Is it possible to change the script for it to update already selected tmdb poster for the new one that is default at tmdb website?

@SSauliusB You can remove the check for Gracenote in the script.

@KevinBarselaar
Copy link

KevinBarselaar commented Nov 25, 2024

I keep getting the following logs:
Zombieland (2009) Checking art... - Art provider is 'None' for Zombieland. Skipping.

I added 'none' to REPLACE_PROVIDERS but that doesn't seem to work.
How can I use this script to replace 'none' with 'tmdb'?

@DeadSyncLTU
Copy link

I keep getting the following logs: Zombieland (2009) Checking art... - Art provider is 'None' for Zombieland. Skipping.

I added 'none' to REPLACE_PROVIDERS but that doesn't seem to work. How can I use this script to replace 'none' with 'tmdb'?

Hello, had same problem and my solution was adding selected_poster.provider == None

@KevinBarselaar
Copy link

I keep getting the following logs: Zombieland (2009) Checking art... - Art provider is 'None' for Zombieland. Skipping.
I added 'none' to REPLACE_PROVIDERS but that doesn't seem to work. How can I use this script to replace 'none' with 'tmdb'?

Hello, had same problem and my solution was adding selected_poster.provider == None

Thanks! Got it working :)

@deniax2
Copy link

deniax2 commented Nov 25, 2024

Does the script support other overlays then English ones?
For my non English speaking family member I created a library in a different language, but the posters are downloaded in English, whilst the title and description of the movie is in the "correct" language.

tmdb has the image available, for example: https://www.themoviedb.org/movie/533535-deadpool-wolverine?language=uk-UA

@JonnyWong16
Copy link
Author

@KevinBarselaar @DeadSyncLTU I added None to the list.

@JonnyWong16
Copy link
Author

@deniax2 Plex doesn't provide language data for the posters so there is no way to select a specific language.

@JamieShatford
Copy link

Am I right in thinking that this updates my Plex library with the set poster on https://www.themoviedb.org/ ?

If yes, how the hell do I get it working.

@JamieShatford
Copy link

TIA

@china420
Copy link

I am getting this in my log. How do i fix it? thanks

Tautulli Notifiers :: Script returned:
No --rating_key or --library specified. Exiting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment