Collection of utility scripts for managing and auditing Plex libraries, exporting metadata, syncing metadata across servers, and bulk file operations.
forceanalyze.py- Queue analyze jobs for all movie and TV libraries.forceanalyzetv.py- Refresh and analyze TV episodes, optionally resuming from a specific file.voiceanalyzed.py- List movies inMoviesthat appear to be missing voice/audio analysis metadata.plexUpdateMovie.py- Bulk update movie titles and sort titles from CSV.UpdateMovieSort.py- Bulk update movie sort titles from an export CSV.plexMovieExport.py- Export movie metadata and file paths to CSV.plexTvExport.py- Export detailed TV episode metadata and file paths to CSV.plexGetTVShows.py- Export show-level TV metadata and source paths to CSV.findDups.py- Print movies with multiple media files.optimize4K.py- Request Plex optimized versions for detected 4K movies.nothumbnails.py- Find movies missing thumbnails through Plex XML API endpoints.deleteThumbnails.py- Delete video preview thumbnails forTV Shows.tvPoster.py- Download and save show/episode posters to media folders.file_rename.py- Move/rename files in bulk from CSV mapping.plexsync/plex_sync.py- Combined poster download + optional metadata sync between source/target Plex servers.
- Python 3.9+ recommended
- Access to Plex server(s) and valid token(s)
- Network access from the machine running scripts to Plex server URL(s)
Install dependencies:
pip install plexapi requests- Several scripts currently contain hardcoded server URLs, tokens, and absolute file paths.
- Before running anything, replace credentials and paths with your values.
- Consider moving secrets to environment variables and never committing real tokens.
- Test on a small subset/library first before full-library runs.
Most scripts expect:
- Plex URL, example:
http://192.168.1.1:32400 - Plex token (from your Plex account/server)
- Existing library names (for example
Movies,TV Shows)
If names differ on your server, update the script constants accordingly.
Queues analyze() for every item in every movie/show library section.
- Retries on read timeout (
max_retries=3) - Adds a 2-second delay between requests
Run:
python forceanalyze.pyRefreshes and analyzes TV episodes in all show libraries.
- Can resume from a hardcoded
start_file - Skips episodes until that file is found
Run:
python forceanalyzetv.pyScans Movies and prints titles where no stream appears to include audioChannelLayout on stream type 3.
Run:
python voiceanalyzed.pyBulk updates movie titles and sort titles by rating_key from CSV.
Expected CSV columns:
rating_keynew_titlesort_title
Default CSV path in script: C:/Users/craig/Downloads/movie_titles.csv
Run:
python plexUpdateMovie.pyLoads plex_movies_export.csv and updates titleSort for matching Plex ID.
Expected CSV columns:
Plex IDTitle Sort
Run:
python UpdateMovieSort.pyExports movie details to plex_movies_export.csv.
Output columns:
Plex IDTitleYearTitle SortCollectionsEditionIMDb IDFile Path(s)
Run:
python plexMovieExport.pyExports detailed episode data from TV Shows to CSV.
Default output path: C:/Users/craig/Downloads/tv_library_info.csv
Output includes show/season/episode metadata, IMDb IDs, raw file path, shell-quoted path, and file-friendly title.
Run:
python plexTvExport.pyExports one row per TV show to tv_shows.csv in the current working directory.
Output columns:
TitleYearFolder Friendly NameIMDb IDTheTVDB IDTV Show Path
Run:
python plexGetTVShows.pyPrints movies where len(movie.media) > 1 (potential duplicate/multi-file entries).
Run:
python findDups.pyFinds movies with detected 4K resolution and calls Plex optimize() with preset "4K Optimized".
Notes:
- Preset name must exist in your Plex environment.
- Resolution detection depends on
media.videoResolution.
Run:
python optimize4K.pyUses direct Plex XML API requests to identify movies missing thumbnail metadata.
Run:
python nothumbnails.pyCalls deleteMediaPreviews() on the TV Shows library.
Run:
python deleteThumbnails.pyDownloads and writes show/episode poster images into media folders.
Behavior highlights:
- Creates/uses
poster.jpgat show folder level - Writes episode poster files named like:
<Show Title> (YEAR) - sXXeYY - poster.jpg - Skips existing files
Important:
- Script currently prepends
'/Volumes/Media'to derived media paths. This is platform/path specific and likely needs adjustment on Windows/Linux.
Run:
python tvPoster.pyBulk move/rename using CSV mappings.
Expected CSV columns:
old_pathnew_path
Default CSV path in script: C:/Users/craig/Downloads/file_paths.csv
Run:
python file_rename.pyplexsync/plex_sync.py supports:
- Downloading movie/show/episode posters from source Plex
- Optional metadata sync (title + sort title) from source to target Plex using library mapping
python plexsync/plex_sync.py --source-url http://SOURCE:32400 --source-token TOKENOptional:
--target-url http://TARGET:32400--target-token TARGET_TOKEN--media-path /media--skip-posters--skip-sync--library-mapping '{"Movies":"Peliculas","TV Shows":"Series"}'--library-mapping-file plexsync/library_mapping.json
PLEX_SOURCE_URLPLEX_SOURCE_TOKENPLEX_TARGET_URLPLEX_TARGET_TOKENMEDIA_PATH(default/media)LIBRARY_MAPPING(JSON string)LIBRARY_MAPPING_FILE(path to JSON file)
From plexsync/:
docker compose up --buildCurrent compose files:
- Mount media path to
/media - Mount
library_mapping.jsonto/app/library_mapping.json - Set source/target Plex env vars
Update docker-compose.yml values before running in your environment.
- Replace all hardcoded tokens/URLs with environment variables.
- Add
requirements.txt(orpyproject.toml) with pinned dependencies. - Add a dry-run mode to destructive/bulk-update scripts.
- Add logging and per-script argument parsing (
argparse) for safer repeated use.