-
-
Save JonnyWong16/9640557cf459896a8b7e1da8863b0485 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
''' | |
Description: Saves poster and art images from Plex to same folder as the media files. | |
Author: /u/SwiftPanda16 | |
Requires: plexapi, tqdm (optional) | |
Usage: | |
* Save posters for an entire library: | |
python save_posters.py --library "TV Shows" --poster | |
* Save art for an entire library: | |
python save_posters.py --library "Music" --art | |
* Save posters and art for an entire library: | |
python save_posters.py --library "Movies" --poster --art | |
* Save posters and art for a specific media type in a library: | |
python save_posters.py --library "TV Shows" --libtype season --poster --art | |
* Save posters for a specific item: | |
python save_posters.py --rating_key 1234 --poster | |
* Save art for a specific item: | |
python save_posters.py --rating_key 1234 --art | |
* Save posters and art for a specific item: | |
python save_posters.py --rating_key 1234 --poster --art | |
''' | |
import argparse | |
from pathlib import Path | |
from plexapi.server import PlexServer | |
from plexapi.utils import download | |
PLEX_URL = 'http://localhost:32400' | |
PLEX_TOKEN = 'XXXXXXXXXXXXXXXXXXXX' | |
# Specify the mapped docker folder paths {host: container}. Leave blank {} if non-docker. | |
MAPPED_FOLDERS = { | |
'/mnt/movies': '/movies', | |
'/mnt/tvshows': '/tv', | |
} | |
_MAPPED_FOLDERS = {Path(host): Path(container) for host, container in MAPPED_FOLDERS.items()} | |
def map_path(file_path): | |
for host, container in _MAPPED_FOLDERS.items(): | |
if container in file_path.parents: | |
return host / file_path.relative_to(container) | |
return file_path | |
def save_library(library, libtype=None, poster=False, art=False): | |
for item in library.all(libtype=libtype, includeGuids=False): | |
save_item(item, poster=poster, art=art) | |
def save_item(item, poster=False, art=False): | |
if hasattr(item, 'locations'): | |
file_path = Path(item.locations[0]) | |
else: | |
file_path = Path(next(iter(item)).locations[0]) | |
save_path = map_path(file_path) | |
if save_path.is_file(): | |
save_path = save_path.parent | |
if poster: | |
save_item_poster(item, save_path) | |
if art: | |
save_item_art(item, save_path) | |
def save_item_poster(item, save_path): | |
print(f"Downloading poster for {item.title} to {save_path}") | |
try: | |
download( | |
url=item.posterUrl, | |
token=plex._token, | |
filename='poster.jpg', | |
savepath=save_path, | |
showstatus=True # Requires `tqdm` package | |
) | |
except Exception as e: | |
print(f"Failed to download poster for {item.title}: {e}") | |
def save_item_art(item, save_path): | |
print(f"Downloading art for {item.title} to {save_path}") | |
try: | |
download( | |
url=item.artUrl, | |
token=plex._token, | |
filename='background.jpg', | |
savepath=save_path, | |
showstatus=True # Requires `tqdm` package | |
) | |
except Exception as e: | |
print(f"Failed to download art for {item.title}: {e}") | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--rating_key', type=int) | |
parser.add_argument('--library') | |
parser.add_argument('--libtype', choices=['movie', 'show', 'season', 'artist', 'album']) | |
parser.add_argument('--poster', action='store_true') | |
parser.add_argument('--art', action='store_true') | |
opts = parser.parse_args() | |
plex = PlexServer(PLEX_URL, PLEX_TOKEN) | |
if opts.rating_key: | |
item = plex.fetchItem(opts.rating_key) | |
save_item(item, opts.poster, opts.art) | |
elif opts.library: | |
library = plex.library.section(opts.library) | |
save_library(library, opts.libtype, opts.poster, opts.art) | |
else: | |
print("No --rating_key or --library specified. Exiting.") |
Updated with separate --poster
and --art
flags. I have not tested it myself.
Updated with separate
--poster
and--art
flags. I have not tested it myself.
I've tested it and it runs as it should, no issues and it's great do be able to save both poster and art with the same command. Thank you very much!
Edit:
Only change I've made is that I've changed "filename='background.jpg'," to "filename='art.jpg'," since there is nowhere else in the script it's referred to as "background", only "art".
Wow this script is awesome. Took several hours on a large library, but worked beautifully. The only feature its missing is the ability to add poster.jpg to newly added shows/movies without redoing the entire library (maybe an --only-missing parameter that if exists=poster.jpg, skip).
I got around the half day wait/ full load by using a bash script to search library for folders not containing poster.jpg >> list, looping that list into a plexapi command to lookup the ratingKey >> list and looping that and calling your script with rating_key parameter. Works fine unless there are weird characters in the name (and I had to remove the year as well or not found), but would be much cleaner if your script could optionally check for an existing poster.jpg. Thank you very much for your work on this, I now have your script running daily to add posters as new items arrive.
Hi, @JonnyWong16, I see that select_tmdb_poster.py got a revision last year so that you can now use "--art" with it to also have changed poster art. Is it possible to do the same with this script, make it work for both art and poster? Right now I have two scripts, this one "save_posters.py" and one I've called "save_arts.py" which is just "save_posters.py" but I've replaced every occurence of "poster" with "art". If possible, it would be nice to have one script that does both.