From 47b828f271c707c6276a2b3b277cfadadfd2026b Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 30 Mar 2025 19:29:30 -0700 Subject: [PATCH] Add utility/save_posters.py --- utility/save_posters.py | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 utility/save_posters.py diff --git a/utility/save_posters.py b/utility/save_posters.py new file mode 100644 index 0000000..8334f21 --- /dev/null +++ b/utility/save_posters.py @@ -0,0 +1,121 @@ +#!/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.")